127

In my App, I create a custom BroadcastReceiver and register it to my Context manually via Context.registerReceiver. I also have an AsyncTask that dispatches notifier-Intents via Context.sendBroadcast. The intents are sent from a non-UI worker thread, but it seems that BroadcastReceiver.onReceive (which receives said Intents) always runs in the UI thread (which is good for me). Is this guaranteed or should I not rely on that?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Hannes Struß
  • 1,560
  • 2
  • 13
  • 20

4 Answers4

184

Does BroadcastReceiver.onReceive always run in the UI thread?

Yes.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • 9
    is this documented somewhere? – Hannes Struß Apr 26 '11 at 14:24
  • 19
    @hannes: 99.44% of the time, if Android is calling your code, it is on the main application thread. All lifecycle methods (e.g., `onCreate()`, `onReceive()`) are called on the main application thread. And, it is documented in the docs for `onReceive()`: http://goo.gl/8kPuH – CommonsWare Apr 26 '11 at 14:41
  • 2
    ok, I'm just interpreting the "is normally called within the main thread" from the docs as "always" and hope things won't break ;-) Thanks! – Hannes Struß Apr 26 '11 at 16:19
  • 4
    @Hannes Struß: I do not know why they hedged their language with "normally". I cannot think of any case where `onReceive()` is called on a thread other than the main application ("UI") thread. – CommonsWare Apr 26 '11 at 16:30
  • @CommonsWare Is is anything wrong if we start a thread inside the broadcastReceiver's `onReceive()` method. Will the thread break after `onReceive()` method returns? – Dharmendra Aug 25 '12 at 05:39
  • 1
    @Dharmendra: If the receiver is registered in the manifest (vs. `registerReceiver()`) it is not safe for it to fork a thread. Android may terminate the process at any point after `onReceive()` ends, particularly if there are no other components running. – CommonsWare Aug 25 '12 at 11:05
  • @CommonsWare So according to you thread is safe in broadcast if we have registered a broadcast receiver using `registerReceiver()`?. As I have some blocking code in broadcast receiver and it may be take 1 or 2 secs so I am using a thread in the broadcast receiver so little worried about this. Between I am registering a broadcast receiver using IntentFilter at runtime. – Dharmendra Aug 25 '12 at 13:06
  • @Dharmendra: For `registerReceiver()`, the component that called `registerReceiver()` is really the one that "owns" the thread and is responsible for its cleanup. – CommonsWare Aug 25 '12 at 13:28
  • 35
    @CommonsWare: "I cannot think of any case where onReceive() is called on a thread other than the main application ("UI") thread" -- the case is if the BroadcastReceiver is registered using registerReceiver(BroadcastReceiver, IntentFilter, String, Handler), the handler argument is not null, and refers to a handler created in a thread other than the main application thread. – Jules Mar 03 '13 at 14:36
  • 2
    @Jules: Ah, very true -- my apologies. – CommonsWare Mar 03 '13 at 14:49
  • 1
    @CommonsWare is it possible to make the broadcastReceiver work on a background thread, but without setting it from code (meaning from the manifest) ? i've noticed that is a function called "goAsync" , but it's available only from API 11 . – android developer Mar 04 '14 at 08:59
  • 2
    @androiddeveloper: "is it possible to make the broadcastReceiver work on a background thread, but without setting it from code (meaning from the manifest) ?" -- no. "i've noticed that is a function called "goAsync" , but it's available only from API 11" -- you're welcome to play with that. I find that the documentation for `goAsync()` is a bit lacking in specifics, and so I prefer to use other means, such as delegating the work to a service. – CommonsWare Mar 04 '14 at 11:58
  • @CommonsWare,Hi, please explain what if we are registering it on a separate thread .? – eRaisedToX Mar 08 '17 at 09:05
  • @eRaisedToX: It does not matter what thread you call `registerReceiver()` on. If you use the versions of `registerReceiver()` that take a `Handler`, the thread associated with that `Handler` (e.g., a `HandlerThread`) will be used for calling `onReceive()` of your receiver. Otherwise, it will be the main application thread. – CommonsWare Mar 08 '17 at 11:45
  • 2
    If you use `LocalBroadcastManager.getInstance(this).registerReceiver()` and `sendBroadcastSync()`, then `onReceive()` runs on the thread of the broadcast sender. In my app's case that means it is sometimes the main thread and sometimes a background thread. – jk7 Mar 17 '17 at 17:21
  • All four android component - (Activity, Service, BroadCastReceiver, ContentProvider) run on UI Thread by default. Its documented in the official Android Developer docs – Rohit Singh Jan 27 '19 at 07:26
  • A question. If I dinamically register a broadcast (or not, anyways), how is the broadcast receiver executed on the main thread? Is that main thread not running the stuff I told it to? Like, I'm doing a loop in the main thread (use the imagination, since in reality is a bad idea xD) - can I still receive the broadcast? If I can't, why? I think I'm confused. If the main thread is executing the instructions from something and a broadcast comes, what happens? The execution of my stuff is stopped some time to time to check for broadcasts? Concurrency in the same thread? – Edw590 Dec 23 '21 at 21:01
  • 1
    @DADi590: "how is the broadcast receiver executed on the main thread?" -- objects are not executed on threads. Methods are. `onReceive()` of your receiver will be called on the main application thread, just like `onCreate()` and other lifecycle events of `Activity` and `Service`. "can I still receive the broadcast?" -- `onReceive()` will not be called. "If I can't, why? " -- because you are tying up the main application thread, so none of those sorts of callbacks can be called (and the framework can't do other relevant work on that thread). – CommonsWare Dec 23 '21 at 21:57
  • Thanks! Though, how are things all ran on the main thread. I code a program in C. How can it receive a call or check for it if I didn't write that on it? Unless maybe the execution of my code is paused from time to time to check for a broadcast and then continue the execution of my code. Am I explaining well enough so that you could say something I could read? I'm just confused how multiple things are done on the main thread. Is it a while loop waiting for a message to come? A gigantic loop with broadcast checks each iteration and my program on it too somehow? Sorry for the dumb question... – Edw590 Dec 24 '21 at 01:12
  • 1
    @DADi590: "I code a program in C" -- I am unclear how this pertains to registering broadcast receivers and being called with `onReceive()`, as all of that usually is in Java or Kotlin. "Is it a while loop waiting for a message to come?" -- actually, yes (see `Looper`). "A gigantic loop with broadcast checks each iteration and my program on it too somehow?" -- the main application thread pulls messages off of a queue and calls methods on your objects to let you do work related to those messages. If you tie up the main application thread, it can no longer do that. – CommonsWare Dec 24 '21 at 12:32
  • 1
    Reading what Looper is about (https://stackoverflow.com/a/34522758/8228163) seems to have helped! A program written in C was because it's a thread and it executes what I tell it to and terminates. In Android, it seems it's not like that, and that's what was confusing me. Main thread, which doesn't end when all my functions end (weird) executes things in the middle of my functions. Now I get why. The Looper takes care of that --> a queue of tasks. When one finishes, wait until there is more to do, or the thread (and app) would terminate after drawing the interface (useful). Thank you!!! – Edw590 Jan 05 '22 at 01:00
80

Since you dynamically register the receiver you can specify that another thread (other than the UI thread) handles the onReceive(). This is done through the Handler parameter of registerReceiver().

That said, if you did not do specify another Handler, it will get handled on UI thread always.

AADProgramming
  • 6,077
  • 11
  • 38
  • 58
TommyTh
  • 1,102
  • 9
  • 13
69

Does BroadcastReceiver.onReceive always run in the UI thread?

Usually, it all depends 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
  • 3
    After looking at this option for a while, I eventually realized that LocalBroadcastManager does not support using a custom handler. So if you're using a LBM instead of a context to register your receiver, this approach does not apply. Unfortunately, in that case it seems our only option left is to use a Service to get on the background and avoid the ANRs that receivers trigger after 10s of inactivity. – gMale Mar 28 '17 at 17:22
10

As the previous answers correctly stated onReceive will run on the thread it's registered with if the flavour of registerReceiver() that accepts a handler is called - otherwise on the main thread.

Except if the receiver is registered with the LocalBroadcastManager and the broadcast is via sendBroadcastSync - where it will apparently run on the thread that calls sendBroadcastSync.

Community
  • 1
  • 1
Mr_and_Mrs_D
  • 32,208
  • 39
  • 178
  • 361
  • I am not agree with the part `and the broadcast is via sendBroadcastSync`. When we use `LocalBroadcastManager` to register the reciever, it must be called by main thread whether use `sendBroadcastSync` or `sendBroadcast`. So the key is that using `LocalBroadcastManager` to register. Am I right? – kidoher Sep 10 '15 at 09:37
  • @kidoher: Did you follow the code links here: http://stackoverflow.com/q/20820244/281545 ? – Mr_and_Mrs_D Sep 10 '15 at 19:21