Чи завжди BroadcastReceiver.onReceive працює в потоці інтерфейсу?


117

У своєму додатку я створюю користувальницький BroadcastReceiverі реєструю його до свого контексту вручну через Context.registerReceiver. У мене також є повідомлення, AsyncTaskяке розсилає сповіщувач-Intents через Context.sendBroadcast. Ці наміри надсилаються з потоку робочого потоку, який не є користувальницьким інтерфейсом, але здається, що BroadcastReceiver.onReceive(який отримує згадані Intents) завжди працює в потоці інтерфейсу користувача (що добре для мене). Це гарантується чи не слід на це покладатися?

Відповіді:


163

Чи завжди BroadcastReceiver.onReceive працює в потоці інтерфейсу?

Так.


9
це десь задокументовано?
Hannes Struß

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

2
ОК, я просто трактую "зазвичай називається в основній темі" з документів як "завжди" і сподіваюсь, що справи не зламаються ;-) Дякую!
Hannes Struß

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

31
@CommonsWare: "Я не можу придумати жоден випадок, коли onReceive () викликається потоком, відмінним від основного потоку програми (" UI ")", - це випадки, якщо BroadcastReceiver зареєстрований за допомогою registerReceiver (BroadcastReceiver, IntentFilter, String, Обробник), аргумент обробника не є нульовим і стосується обробника, створеного в потоці, відмінному від основного потоку програми.
Жуль

76

Оскільки ви динамічно реєструєте приймач, ви можете вказати, що інший потік (крім потоку інтерфейсу) обробляє onReceive(). Це робиться через параметр Handler registerReceiver () .

Тим не менш, якщо ви не вказали інший обробник, він буде оброблятися в потоці інтерфейсу завжди.


Так. Здається, що ваша здатність змінювати це через параметр Handler, тому вони "хеджували" свою мову в документах.
Ендрю Макензі

64

Чи завжди BroadcastReceiver.onReceive працює в потоці інтерфейсу?

Зазвичай, все залежить від того, як ви це зареєструєте.

Якщо ви зареєструєте своє BroadcastReceiverвикористання:

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

Він запускатиметься в потоці основної активності (він же потоком UI) .

Якщо ви зареєструєте своє 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 широкомовна передача, Планувальник обробника)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.