AudioManager отправляет сообщение обработчику в мертвом потоке?

Я пытаюсь программно увеличить громкость до максимального значения потока STREAM_MUSIC, но при этом возникает проблема "Отправка сообщения обработчику в мертвом потоке". Кроме того, кажется, что он не увеличивает громкость в 100% случаев, хотя, когда я получаю эту ошибку, он увеличивает ее БОЛЬШИНСТВО времени.

Код:

System.out.println("Maximum volume for this stream is: "+maxstreamvol+" and it used to be set to: "+currentvol);     
final AudioManager am = (AudioManager)this.getSystemService(Context.AUDIO_SERVICE);
am.setStreamVolume(AudioManager.STREAM_MUSIC, maxstreamvol, AudioManager.FLAG_SHOW_UI);
am.setStreamSolo(AudioManager.STREAM_MUSIC, true);
System.out.println("Volume Raised!"); 

После поиска в Google кажется, что эта ошибка связана с многопоточными ситуациями... Код на этом этапе должен выполняться в потоке пользовательского интерфейса.

На самом деле, я даже окружил его:

runOnUiThread(new Runnable() {

    public void run() {
        // code_goes_here
    }
});

И это вызвало ту же ошибку. Ошибка, которую я вижу, заключается в следующем:

I/System.out(24949): Maximum volume for this stream is: 15 and it used to be set to: 0
W/MessageQueue(  490): Handler (android.media.AudioManager$FocusEventHandlerDelegate$1) {42b52f28} sending message to a Handler on a dead thread
W/MessageQueue(  490): java.lang.RuntimeException: Handler (android.media.AudioManager$FocusEventHandlerDelegate$1) {42b52f28} sending message to a Handler on a dead thread
W/MessageQueue(  490):  at android.os.MessageQueue.enqueueMessage(MessageQueue.java:294)
W/MessageQueue(  490):  at android.os.Handler.enqueueMessage(Handler.java:618)
W/MessageQueue(  490):  at android.os.Handler.sendMessageAtTime(Handler.java:587)
W/MessageQueue(  490):  at android.os.Handler.sendMessageDelayed(Handler.java:558)
W/MessageQueue(  490):  at android.os.Handler.sendMessage(Handler.java:495)
W/MessageQueue(  490):  at android.media.AudioManager$1.dispatchAudioFocusChange(AudioManager.java:1894)
W/MessageQueue(  490):  at android.media.IAudioFocusDispatcher$Stub.onTransact(IAudioFocusDispatcher.java:57)
W/MessageQueue(  490):  at android.os.Binder.execTransact(Binder.java:351)
W/MessageQueue(  490):  at dalvik.system.NativeStart.run(Native Method)
I/System.out(24949): Volume Raised!

Кто-нибудь знает, что здесь происходит?


person Dwebtron    schedule 11.03.2013    source источник
comment
Вы запрашиваете Audio Focus в своем коде? Также попробуйте использовать applicationContext, например. (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE);   -  person iTech    schedule 12.03.2013
comment
Я пробовал это и тестировал. Это заставило сбой обработчика исчезнуть, но по-прежнему не позволяет мне надежно поднять звук...   -  person Dwebtron    schedule 12.03.2013
comment
Редактировать: оказалось, что звук не поднимается по моей собственной вине, так как я вызвал состояние гонки! Ой! (Я забыл отредактировать это некоторое время назад)   -  person Dwebtron    schedule 22.02.2014


Ответы (2)


Ваша проблема может быть связана с той, о которой сообщалось в этой теме - onPostExecute не вызывается в AsyncTask (исключение времени выполнения обработчика)

Отображение изменения фокуса звука вызывает событие пользовательского интерфейса, которое Android не может завершить. Не сразу понятно, почему так. Возможно, менеджер аудио был получен с одним контекстом, а всплывающее уведомление, показывающее громкость, выполняется в другом контексте? Быстрое и грязное изменение — поменять флаг на FLAG_VIBRATE и проверить, имеет ли это значение. Это сузило бы проблему до обновления пользовательского интерфейса, над которым вы затем сможете работать.

person Deepak Bala    schedule 12.03.2013
comment
На самом деле, я только что добавил AudioManager.FLAG_SHOW_UI, чтобы убедиться, что звук поднимается правильно. Раньше я вызывал setStreamVolume с флагом '0'. На самом деле, я рассчитываю на то, что все это произойдет за кадром, поэтому я не возражаю, если мне придется вернуться к флагу «0».... но, похоже, это тоже не работает на 100%. Таким образом, флаги в 0 или AudioManager.FLAG_SHOW_UI, похоже, дают один и тот же результат, конечно, один с индикацией пользовательского интерфейса, а другой без. - person Dwebtron; 12.03.2013
comment
Запрошен ли AudioManager в другом месте вашего приложения? Я предполагаю, что фрагмент кода, который вы разместили изначально, находится внутри действия. Я покопался в коде Impl и обнаружил, что аудио-менеджер использует внутренний цикл и обработчик для оповещения фреймворка об изменении фокуса звука. Интересно, может ли внутренний обработчик, кэшированный с неправильным контекстом, вызвать эту проблему. - person Deepak Bala; 12.03.2013
comment
Я не уверен... но это возможно. Как бы я проверил и / или исправил это, если бы это было так? Всякий раз, когда я вызываю setStreamVolume, предыдущая строка всегда следующая: final AudioManager am = (AudioManager)getApplicationContext().getSystemService(Context.AUDIO_SERVICE); - person Dwebtron; 12.03.2013
comment
У AsyncTasks была эта проблема, когда они создавались из фоновых потоков. Если первая асинхронная задача в вашей программе НЕ создается из потока пользовательского интерфейса, возникает эта проблема. Аудиоменеджеры могут пострадать от чего-то подобного. Для проверки создайте класс Application для своего приложения; зарегистрировать его в манифесте андроида; и получить системную службу аудио-менеджера из метода onCreate(). Это может правильно создать внутренний цикл и обработчик. - person Deepak Bala; 12.03.2013
comment
Я пробовал это так: static AudioManager am; void onCreate (Bundle saveInstanceState) { final AudioManager am = (AudioManager) getApplicationContext (). GetSystemService (Context.AUDIO_SERVICE); Но всякий раз, когда я пытаюсь его использовать, возникает исключение NullPointerException... Я делаю что-то не так? - person Dwebtron; 12.03.2013
comment
Вам не обязательно использовать этот экземпляр. Достаточно создать экземпляр только с правильным контекстом, поскольку это правильно установит обработчик внутри аудиоменеджера. Использование контекста приложения для получения аудиосервиса в следующий раз должно решить проблему с обработчиком, и из вашего другого комментария видно, что ошибка больше не возникает. Надежное поднятие звука — еще одна проблема сама по себе. Возможно, будет лучше, если вы поднимете для этого другой вопрос и опубликуете больше кода о том, как получить объем maxstream и т. д. - person Deepak Bala; 13.03.2013

AudioManager использует поток, который был создан, для вызова вашего обратного вызова или выполнения манипуляций с пользовательским интерфейсом (отображение всплывающего уведомления о громкости и т. д.)
(через Looper.myLooper или getMainLooper, см. это).

Поэтому вы должны убедиться, что ваш первый вызов Context.getSystemService(AUDIO_MANAGER) происходит в потоке пользовательского интерфейса.
(Не уверен, что последующие вызовы будут повторно использовать этот экземпляр, но даже если я повторно получу AudioManager, исключение все равно возникнет. )

Сегодня я столкнулся с этой проблемой и решил ее, добавив этот вызов в мой Application.onCreate(). (Чем-то похоже на этот ответ?)

person KenIchi    schedule 31.05.2017