Wird BroadcastReceiver.onReceive immer im UI-Thread ausgeführt?

117

In meiner App erstelle ich eine benutzerdefinierte BroadcastReceiverund registriere sie manuell über in meinem Kontext Context.registerReceiver. Ich habe auch eine AsyncTask, die Notifier-Intents über versendet Context.sendBroadcast. Die Absichten werden von einem Nicht-UI-Worker-Thread gesendet, aber es scheint, dassBroadcastReceiver.onReceive (der empfängt) immer im UI-Thread ausgeführt wird (was gut für mich ist). Ist das garantiert oder sollte ich mich nicht darauf verlassen?

Hannes Struß
quelle

Antworten:

163

Wird BroadcastReceiver.onReceive immer im UI-Thread ausgeführt?

Ja.

CommonsWare
quelle
9
ist das irgendwo dokumentiert?
Hannes Struß
15
@hannes: In 99,44% der Fälle befindet sich Android, wenn es Ihren Code aufruft, im Hauptanwendungsthread. Alle Lebenszyklus Methoden (zB onCreate(), onReceive()) auf dem Hauptanwendungsthread bezeichnet. Und es ist in den Dokumenten dokumentiert für onReceive(): goo.gl/8kPuH
CommonsWare
2
ok, ich interpretiere nur das "wird normalerweise innerhalb des Hauptthreads aufgerufen" aus den Dokumenten als "immer" und hoffe, dass die Dinge nicht kaputt gehen ;-) Danke!
Hannes Struß
4
@Hannes Struß: Ich weiß nicht, warum sie ihre Sprache mit "normal" abgesichert haben. Ich kann mir keinen Fall vorstellen onReceive(), in dem ein anderer Thread als der Hauptanwendungsthread ("UI") aufgerufen wird.
CommonsWare
31
@CommonsWare: "Ich kann mir keinen Fall vorstellen, in dem onReceive () für einen anderen Thread als den Hauptanwendungsthread (" UI ") aufgerufen wird" - der Fall ist, wenn der BroadcastReceiver mit registerReceiver registriert ist (BroadcastReceiver, IntentFilter, String, Handler), das Handler-Argument ist nicht null und bezieht sich auf einen Handler, der in einem anderen Thread als dem Hauptanwendungsthread erstellt wurde.
Jules
76

Da Sie den Empfänger dynamisch registrieren, können Sie angeben, dass ein anderer Thread (außer dem UI-Thread) das behandelt onReceive(). Dies erfolgt über den Handler-Parameter von registerReceiver () .

Wenn Sie jedoch keinen anderen Handler angegeben haben, wird dieser immer im UI-Thread behandelt.

TommyTh
quelle
Ja. Klingt so, als ob Sie es über den Handler-Parameter ändern können, haben sie ihre Sprache in den Dokumenten "abgesichert".
Andrew Mackenzie
64

Wird BroadcastReceiver.onReceive immer im UI-Thread ausgeführt?

Normalerweise hängt alles davon ab, wie Sie es registrieren.

Wenn Sie Ihre BroadcastReceiverVerwendung registrieren :

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

Es wird im Hauptaktivitätsthread (auch als UI-Thread bezeichnet) ausgeführt .

Wenn Sie sich BroadcastReceivermit einem gültigen Handler Lauf auf einem anderen Thread registrieren :

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

Es wird im Kontext Ihres ausgeführt Handler

Beispielsweise:

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

Details hier & hier .

Caner
quelle
3
Nachdem ich mir diese Option eine Weile angesehen hatte, stellte ich schließlich fest, dass LocalBroadcastManager die Verwendung eines benutzerdefinierten Handlers nicht unterstützt. Wenn Sie also ein LBM anstelle eines Kontexts verwenden, um Ihren Empfänger zu registrieren, gilt dieser Ansatz nicht. Leider scheint es in diesem Fall unsere einzige verbleibende Option zu sein, einen Dienst zu verwenden, um in den Hintergrund zu treten und die ANRs zu vermeiden, die Empfänger nach 10 Sekunden Inaktivität auslösen.
gMale
9

Wie die vorherigen Antworten richtig angegeben, onReceivewird auf dem Thread ausgeführt, bei dem es registriert ist, wenn der Geschmack von registerReceiver() , die einen Handler akzeptiert, aufgerufen wird - andernfalls auf dem Hauptthread.

Außer wenn der Empfänger bei der registriert ist LocalBroadcastManagerund die Sendung über erfolgt sendBroadcastSync- wo sie anscheinend auf dem Thread läuft, der anruftsendBroadcastSync.

Mr_and_Mrs_D
quelle
Ich bin mit dem Teil nicht einverstanden and the broadcast is via sendBroadcastSync. Wenn wir LocalBroadcastManagerden Empfänger registrieren, muss er vom Hauptthread aufgerufen werden, ob use sendBroadcastSyncoder sendBroadcast. Der Schlüssel ist also, sich LocalBroadcastManagerzu registrieren. Habe ich recht?
Kidoher
@kidoher: Sind Sie den Code-Links hier gefolgt : stackoverflow.com/q/20820244/281545 ?
Mr_and_Mrs_D
0

JA Context.registerReceiver (BroadcastReceiver-Empfänger, IntentFilter-Filter, String BroadcastPermission, Handler-Scheduler)

Akash
quelle