Всегда ли BroadcastReceiver.onReceive выполняется в потоке пользовательского интерфейса?


117

В своем приложении я создаю заказ BroadcastReceiverи регистрирую его в своем контексте вручную через Context.registerReceiver. У меня также есть программа, AsyncTaskкоторая отправляет уведомления-намерения через Context.sendBroadcast. Намерения отправляются из рабочего потока, не относящегося к пользовательскому интерфейсу, но кажется, что BroadcastReceiver.onReceive(который получает указанные намерения) всегда выполняется в потоке пользовательского интерфейса (что хорошо для меня). Это гарантировано или мне не следует полагаться на это?

Ответы:


163

Всегда ли BroadcastReceiver.onReceive выполняется в потоке пользовательского интерфейса?

Да.


9
это где-то задокументировано?
Ханнес Штрусс,

15
@hannes: 99,44% времени, если Android вызывает ваш код, он находится в основном потоке приложения. Все методы жизненного цикла (например, onCreate(), onReceive()) называется на главном потоке приложения. И это задокументировано в документации для onReceive(): goo.gl/8kPuH
CommonsWare

2
хорошо, я просто интерпретирую «обычно вызывается в основном потоке» из документации как «всегда» и надеюсь, что ничего не сломается ;-) Спасибо!
Ханнес Штрусс

4
@Hannes Struß: Я не знаю, почему они хеджировали свой язык словом «обычно». Я не могу представить себе ни одного случая, когда onReceive()вызывается поток, отличный от потока основного приложения («UI»).
CommonsWare

31
@CommonsWare: «Я не могу придумать ни одного случая, когда onReceive () вызывается в потоке, отличном от потока основного приложения (« UI »)» - это случай, если BroadcastReceiver зарегистрирован с помощью registerReceiver (BroadcastReceiver, IntentFilter, String, Handler), аргумент обработчика не имеет значения NULL и относится к обработчику, созданному в потоке, отличном от основного потока приложения.
Жюль

76

Поскольку вы динамически регистрируете получатель, вы можете указать, что другой поток (кроме потока пользовательского интерфейса) обрабатывает onReceive(). Это делается с помощью параметра Handler функции registerReceiver () .

Тем не менее, если вы не указали другой обработчик, он всегда будет обрабатываться в потоке пользовательского интерфейса.


Да. Похоже, ваша способность изменить его с помощью параметра Handler является причиной того, что они «хеджировали» свой язык в документации.
Эндрю Маккензи,

64

Всегда ли BroadcastReceiver.onReceive выполняется в потоке пользовательского интерфейса?

Обычно все зависит от того, как вы его регистрируете.

Если вы зарегистрируете свое BroadcastReceiverиспользование:

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

Он будет работать в основном потоке активности (он же поток пользовательского интерфейса) .

Если вы зарегистрируете свой BroadcastReceiverдействительный Handler запуск в другом потоке :

registerReceiver (BroadcastReceiver receiver, IntentFilter filter, String broadcastPermission, Handler scheduler)

Он будет работать в контексте вашего Handler

Например:

HandlerThread handlerThread = new HandlerThread("ht");
handlerThread.start();
Looper looper = handlerThread.getLooper();
Handler handler = new Handler(looper);
context.registerReceiver(receiver, filter, null, handler); // Will not run on main thread

Подробности здесь и здесь .


3
Посмотрев на этот вариант некоторое время, я в конце концов понял, что LocalBroadcastManager не поддерживает использование настраиваемого обработчика. Поэтому, если вы используете LBM вместо контекста для регистрации своего приемника, этот подход не применяется. К сожалению, в этом случае кажется, что у нас остается единственный выход - использовать Службу для работы в фоновом режиме и избегать ошибок ANR, которые получатели запускают после 10 секунд бездействия.
gMale

9

Как правильно указано в предыдущих ответах, он onReceiveбудет работать в потоке, в котором он зарегистрирован, если вкус registerReceiver() вызывается , принимающий обработчик, в противном случае в основном потоке.

За исключением случаев, когда получатель зарегистрирован в LocalBroadcastManagerи трансляция осуществляется через sendBroadcastSync- где он, по- видимому, будет работать в потоке, который вызываетsendBroadcastSync.


Я не согласен с этой частью and the broadcast is via sendBroadcastSync. Когда мы используем LocalBroadcastManagerдля регистрации приемника, он должен вызываться основным потоком независимо от того, используется ли sendBroadcastSyncили sendBroadcast. Итак, ключ в том, чтобы использовать LocalBroadcastManagerдля регистрации. Я прав?
kidoher

@kidoher: Вы переходили по ссылкам на код здесь: stackoverflow.com/q/20820244/281545 ?
Mr_and_Mrs_D

0

ДА Context.registerReceiver (приемник BroadcastReceiver, фильтр IntentFilter, String broadcastPermission, планировщик обработчика)

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.