O BroadcastReceiver.onReceive sempre é executado no thread de IU?

117

No meu aplicativo, eu crio um custom BroadcastReceivere o registro no meu Context manualmente via Context.registerReceiver. Eu também tenho um AsyncTaskque despacha Intents notifier via Context.sendBroadcast. Os intents são enviados de um thread de trabalho não-UI, mas parece que BroadcastReceiver.onReceive(que recebe os referidos Intents) sempre é executado no thread de UI (o que é bom para mim). Isso é garantido ou não devo confiar nisso?

Hannes Struß
fonte

Respostas:

163

O BroadcastReceiver.onReceive sempre é executado no thread de IU?

Sim.

CommonsWare
fonte
9
isso está documentado em algum lugar?
Hannes Struß
15
@hannes: 99,44% do tempo, se o Android está chamando seu código, é no thread principal do aplicativo. Todos os métodos do ciclo de vida (por exemplo, onCreate(), onReceive()) são chamados no segmento do aplicativo principal. E, está documentado nos documentos de onReceive(): goo.gl/8kPuH
CommonsWare
2
ok, estou apenas interpretando o "normalmente é chamado dentro do tópico principal" da documentação como "sempre" e espero que as coisas não quebrem ;-) Obrigado!
Hannes Struß
4
@Hannes Struß: Não sei por que eles limitaram sua linguagem com "normalmente". Não consigo pensar em nenhum caso em que onReceive()seja chamado em um thread diferente do thread do aplicativo principal ("UI").
CommonsWare
31
@CommonsWare: "Não consigo pensar em nenhum caso em que onReceive () seja chamado em um thread diferente do thread do aplicativo principal (" UI ")" - o caso é se o BroadcastReceiver é registrado usando registerReceiver (BroadcastReceiver, IntentFilter, String, Handler), o argumento do manipulador não é nulo e se refere a um manipulador criado em um thread diferente do thread principal do aplicativo.
Jules
76

Visto que você registra dinamicamente o receptor, você pode especificar que outro thread (diferente do UI thread) manipule o onReceive(). Isso é feito por meio do parâmetro Handler de registerReceiver () .

Dito isso, se você não especificou outro Handler, ele sempre será tratado no thread de UI.

TommyTh
fonte
Sim. Parece que sua capacidade de alterá-lo por meio do parâmetro Handler é o motivo pelo qual eles "protegeram" o idioma nos documentos.
Andrew Mackenzie
64

O BroadcastReceiver.onReceive sempre é executado no thread de IU?

Normalmente, tudo depende de como você o registra.

Se você registrar seu BroadcastReceiverusando:

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

Ele será executado no thread de atividade principal (também conhecido como thread de interface do usuário) .

Se você registrar seu BroadcastReceiverusando uma Handler execução válida em um thread diferente :

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

Ele será executado no contexto do seu Handler

Por exemplo:

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

Detalhes aqui e aqui .

Caner
fonte
3
Depois de examinar essa opção por um tempo, percebi que LocalBroadcastManager não oferece suporte ao uso de um manipulador personalizado. Portanto, se você estiver usando um LBM em vez de um contexto para registrar seu receptor, esta abordagem não se aplica. Infelizmente, nesse caso, parece que nossa única opção é usar um serviço para ficar em segundo plano e evitar os ANRs que os receptores disparam após 10s de inatividade.
gMale
9

Como as respostas anteriores indicadas corretamente, onReceiveserão executadas no tópico com o qual está registrado se o sabor de registerReceiver()que aceita um manipulador for chamado - caso contrário, no tópico principal.

Exceto se o receptor estiver registrado no LocalBroadcastManagere a transmissão for via sendBroadcastSync- onde aparentemente será executado no thread que chamasendBroadcastSync.

Mr_and_Mrs_D
fonte
Não concordo com a parte and the broadcast is via sendBroadcastSync. Quando usamos LocalBroadcastManagerpara registrar o receptor, ele deve ser chamado por thread principal se usar sendBroadcastSyncou sendBroadcast. Portanto, a chave é usar LocalBroadcastManagerpara se registrar. Estou certo?
kidoher de
@kidoher: Você seguiu os links de código aqui: stackoverflow.com/q/20820244/281545 ?
Mr_and_Mrs_D
0

YES Context.registerReceiver (receptor BroadcastReceiver, filtro IntentFilter, String broadcastPermission, agendador de manipulador)

Akash
fonte