BroadcastReceiver.onReceive s'exécute-t-il toujours dans le thread d'interface utilisateur?

117

Dans mon application, je crée une personnalisation BroadcastReceiveret je l'enregistre manuellement dans mon contexte via Context.registerReceiver. J'ai aussi un AsyncTaskqui envoie les intentions de notification via Context.sendBroadcast. Les intentions sont envoyées à partir d'un thread de travail non-UI, mais il semble que BroadcastReceiver.onReceive(qui reçoit lesdites intentions) s'exécute toujours dans le thread de l'interface utilisateur (ce qui est bon pour moi). Est-ce garanti ou ne devrais-je pas me fier à cela?

Hannes Struß
la source

Réponses:

163

BroadcastReceiver.onReceive s'exécute-t-il toujours dans le thread d'interface utilisateur?

Oui.

CommonsWare
la source
9
est-ce documenté quelque part?
Hannes Struß
15
@hannes: 99,44% du temps, si Android appelle votre code, c'est sur le thread principal de l'application. Toutes les méthodes du cycle de vie (par exemple onCreate(), onReceive()) sont appelés sur le fil de l' application principale. Et, il est documenté dans la documentation pour onReceive(): goo.gl/8kPuH
CommonsWare
2
ok, j'interprète juste le "est normalement appelé dans le fil principal" de la documentation comme "toujours" et j'espère que les choses ne se cassent pas ;-) Merci!
Hannes Struß
4
@Hannes Struß: Je ne sais pas pourquoi ils ont couvert leur langage avec "normalement". Je ne peux penser à aucun cas où onReceive()est appelé sur un thread autre que le thread de l'application principale ("UI").
CommonsWare
31
@CommonsWare: "Je ne peux penser à aucun cas où onReceive () est appelé sur un thread autre que le thread de l'application principale (" UI ")" - le cas est si le BroadcastReceiver est enregistré à l'aide de registerReceiver (BroadcastReceiver, IntentFilter, String, Handler), l'argument du gestionnaire n'est pas nul et fait référence à un gestionnaire créé dans un thread autre que le thread d'application principal.
Jules
76

Puisque vous enregistrez dynamiquement le récepteur, vous pouvez spécifier qu'un autre thread (autre que le thread d'interface utilisateur) gère le onReceive(). Cela se fait via le paramètre Handler de registerReceiver () .

Cela dit, si vous n'avez pas spécifié d'autre gestionnaire, il sera toujours géré sur le thread d'interface utilisateur.

TommyTh
la source
Oui. On dirait que votre capacité à le changer via le paramètre Handler est la raison pour laquelle ils ont "couvert" leur langue dans la documentation.
Andrew Mackenzie
64

BroadcastReceiver.onReceive s'exécute-t-il toujours dans le thread d'interface utilisateur?

Habituellement, tout dépend de la manière dont vous l'enregistrez.

Si vous enregistrez votre BroadcastReceiverutilisation:

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

Il s'exécutera dans le thread d'activité principal (aka thread UI) .

Si vous enregistrez votre en BroadcastReceiverutilisant une Handler exécution valide sur un autre thread :

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

Il fonctionnera dans le contexte de votre Handler

Par exemple:

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

Détails ici et ici .

Caner
la source
3
Après avoir examiné cette option pendant un moment, j'ai finalement réalisé que LocalBroadcastManager ne prend pas en charge l'utilisation d'un gestionnaire personnalisé. Donc, si vous utilisez un LBM au lieu d'un contexte pour enregistrer votre récepteur, cette approche ne s'applique pas. Malheureusement, dans ce cas, il semble que notre seule option restante soit d'utiliser un service pour passer en arrière-plan et éviter les ANR que les récepteurs déclenchent après 10 s d'inactivité.
gMale
9

Comme les réponses précédentes correctement énoncées onReceiveseront exécutées sur le thread avec registerReceiver()lequel il est enregistré si la saveur de cela accepte un gestionnaire est appelé - sinon sur le thread principal.

Sauf si le récepteur est enregistré auprès de LocalBroadcastManageret que la diffusion se fait via sendBroadcastSync- où il fonctionnera apparemment sur le thread qui appellesendBroadcastSync.

Mr_and_Mrs_D
la source
Je ne suis pas d'accord avec la partie and the broadcast is via sendBroadcastSync. Lorsque nous utilisons LocalBroadcastManagerpour enregistrer le récepteur, il doit être appelé par le thread principal, que ce soit use sendBroadcastSyncou sendBroadcast. Donc, la clé est d'utiliser LocalBroadcastManagerpour vous inscrire. Ai-je raison?
kidoher
@kidoher: Avez-vous suivi les liens de code ici: stackoverflow.com/q/20820244/281545 ?
Mr_and_Mrs_D
0

OUI Context.registerReceiver (récepteur BroadcastReceiver, filtre IntentFilter, String broadcastPermission, planificateur de gestionnaire)

Akash
la source