Apakah BroadcastReceiver.onReceive selalu berjalan di UI thread?

117

Di App saya, saya membuat custom BroadcastReceiverdan mendaftarkannya ke Context saya secara manual melalui Context.registerReceiver. Saya juga memiliki AsyncTaskyang mengirimkan notifier-Intents via Context.sendBroadcast. Maksud dikirim dari utas pekerja non-UI, tetapi tampaknya BroadcastReceiver.onReceive(yang menerima maksud tersebut ) selalu berjalan di utas UI (yang bagus untuk saya). Apakah ini dijamin atau haruskah saya tidak mengandalkan itu?

Hannes Struß
sumber

Jawaban:

163

Apakah BroadcastReceiver.onReceive selalu berjalan di UI thread?

Iya.

CommonsWare
sumber
9
apakah ini didokumentasikan di suatu tempat?
Hannes Struß
15
@hannes: 99,44% dari waktu, jika Android memanggil kode Anda, itu ada di utas aplikasi utama. Semua metode siklus hidup (misalnya onCreate(), onReceive()) dipanggil pada thread aplikasi utama. Dan, itu didokumentasikan di dokumen untuk onReceive(): goo.gl/8kPuH
CommonsWare
2
ok, saya hanya menafsirkan "biasanya dipanggil di dalam utas utama" dari dokumen sebagai "selalu" dan berharap semuanya tidak akan rusak ;-) Terima kasih!
Hannes Struß
4
@Hannes Struß: Saya tidak tahu mengapa mereka membatasi bahasa mereka dengan "normal". Saya tidak bisa memikirkan kasus apa pun di mana onReceive()dipanggil pada utas selain utas aplikasi utama ("UI").
CommonsWare
31
@CommonsWare: "Saya tidak dapat memikirkan kasus apa pun di mana onReceive () dipanggil pada utas selain utas aplikasi utama (" UI ")" - kasusnya adalah jika BroadcastReceiver terdaftar menggunakan registerReceiver (BroadcastReceiver, IntentFilter, String, Handler), argumen handler bukan null, dan merujuk ke handler yang dibuat di thread selain thread aplikasi utama.
Jules
76

Karena Anda mendaftarkan penerima secara dinamis, Anda dapat menentukan bahwa utas lain (selain utas UI) menangani onReceive(). Ini dilakukan melalui parameter Handler dari registerReceiver () .

Karena itu, jika Anda tidak menentukan Handler lain, itu akan selalu ditangani pada UI thread.

TommyTh
sumber
Iya. Kedengarannya seperti kemampuan Anda untuk mengubahnya melalui parameter Handler adalah alasan mengapa mereka "melindungi" bahasa mereka di dokumen.
Andrew Mackenzie
64

Apakah BroadcastReceiver.onReceive selalu berjalan di UI thread?

Biasanya, semuanya tergantung bagaimana Anda mendaftarkannya.

Jika Anda mendaftar BroadcastReceivermenggunakan:

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

Ini akan berjalan di utas aktivitas utama (alias utas UI) .

Jika Anda mendaftar BroadcastReceivermenggunakan valid yang Handler berjalan di utas berbeda :

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

Ini akan berjalan dalam konteks Anda Handler

Sebagai contoh:

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

Detail di sini & di sini .

Caner
sumber
3
Setelah melihat opsi ini beberapa saat, saya akhirnya menyadari bahwa LocalBroadcastManager tidak mendukung penggunaan penangan khusus. Jadi jika Anda menggunakan LBM alih-alih konteks untuk mendaftarkan penerima Anda, pendekatan ini tidak berlaku. Sayangnya, dalam hal ini tampaknya satu-satunya pilihan kami yang tersisa adalah menggunakan Layanan untuk berada di latar belakang dan menghindari ANR yang dipicu oleh penerima setelah tidak aktif selama 10 detik.
gMale
9

Karena jawaban sebelumnya yang dinyatakan dengan benar onReceiveakan berjalan di utas yang didaftarkan jika flavor registerReceiver()yang menerima penangan dipanggil - sebaliknya di utas utama.

Kecuali jika penerima terdaftar dengan LocalBroadcastManagerdan siaran melalui sendBroadcastSync- di mana tampaknya akan berjalan di utas yang memanggilsendBroadcastSync.

Mr_and_Mrs_D
sumber
Saya tidak setuju dengan bagian itu and the broadcast is via sendBroadcastSync. Ketika kami gunakan LocalBroadcastManageruntuk mendaftarkan penerima, itu harus dipanggil oleh utas utama apakah menggunakan sendBroadcastSyncatau sendBroadcast. Jadi kuncinya adalah menggunakan LocalBroadcastManageruntuk mendaftar. Apakah saya benar?
kidoher
@ kidoher: Apakah Anda mengikuti tautan kode di sini: stackoverflow.com/q/20820244/281545 ?
Mr_and_Mrs_D
0

YES Context.registerReceiver (penerima BroadcastReceiver, filter IntentFilter, String broadcastPermission, Handler scheduler)

Akash
sumber