45

If I have an inner class that extends BroadcastReceiver within my Service class, should I care about synchronization, when the BroadcastReceiver class reads/writes to objects from the Service class? Or to put it in another way: Are BroadacstReceiver's onReceive() Methods started in an extra thread?

Flow
  • 23,572
  • 15
  • 99
  • 156

5 Answers5

41

The onReceive() method is always called on the main thread (which is also referred to as "UI thread"), unless you requested it to be scheduled on a different thread using the registerReceiver() variant:

Context.registerReceiver(BroadcastReceiver receiver,
                         IntentFilter filter,
                         String broadcastPermission,
                         Handler scheduler)
Flow
  • 23,572
  • 15
  • 99
  • 156
Nick Pelly
  • 466
  • 5
  • 3
27

Are Android's BroadcastReceivers started in a new thread?

Usually but not always, it all depends on how you register it.

If you register your BroadcastReceiver using:

registerReceiver(BroadcastReceiver receiver, IntentFilter filter)

It will run in the main activity thread(aka UI thread).

If you register your BroadcastReceiver using a valid Handler running on a different thread:

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

It will run in the context of your Handler

For example:

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 here & here.

Caner
  • 57,267
  • 35
  • 174
  • 180
18

The onReceive() method is called on the main thread. So, in case all your access to the service class is done from within the main thread, you don't need any synchronization.

Stephan
  • 7,360
  • 37
  • 46
  • 4
    So the answer to his question is no! The `onReceive` method does not run on an extra thread. – Joseph Earl Mar 22 '11 at 20:14
  • Android Cookbook: Be aware that the BroadcastReceiver runs on the same thread that the intent is Broadcast on; in our example this is the main/GUI thread! – JohnyTex Oct 02 '14 at 09:05
  • @Stephan, so operation of *Toast.makeText(..data)* in `onReceive` where *data* is passed from a background thread in service is thread safe? – Plain_Dude_Sleeping_Alone Sep 08 '16 at 11:31
3

Android Broadcast receivers are by default start in GUI thread (main thread) if you use RegisterReceiver(broadcastReceiver, intentFilter).

But it can be run in a worker thread as follows;

When using a HandlerThread, be sure to exit the thread after unregistering the BroadcastReceiver. If not, File Descriptor (FD) leaks occur in Linux level and finally the application gets crashed if continue to Register / Unregister.

unregisterReceiver(...);

Then looper.quit(); Or looper.quitSafely();

private Handler broadcastReceiverHandler = null;
private HandlerThread broadcastReceiverThread = null;
private Looper broadcastReceiverThreadLooper = null;

private BroadcastReceiver broadcastReceiverReadScans = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {

    }
}

private void registerForIntents() {
    broadcastReceiverThread = new HandlerThread("THREAD_NAME");//Create a thread for BroadcastReceiver
    broadcastReceiverThread.start();

    broadcastReceiverThreadLooper = broadcastReceiverThread.getLooper();
    broadcastReceiverHandler = new Handler(broadcastReceiverThreadLooper);

    IntentFilter filterScanReads = new IntentFilter();
    filterScanReads.addAction("ACTION_SCAN_READ");
    filterScanReads.addCategory("CATEGORY_SCAN");

    context.registerReceiver(broadcastReceiverReadScans, filterScanReads, null, broadcastReceiverHandler);
}

private void unregisterIntents() {
    context.unregisterReceiver(broadcastReceiverReadScans);
    broadcastReceiverThreadLooper.quit();//Don't forget
}
Samantha
  • 921
  • 9
  • 12
1

Also, you can specify the "android:process" receiver element attribute in the AndroidManifest.xml. See here. That way you can specify that the receiver runs as a separate process and isn't tied to the main UI thread.

stoker
  • 19
  • 2