Does BroadcastReceiver.onReceive always run in the UI thread?
Asked Answered
W

4

128

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?

Want answered 15/4, 2011 at 9:0 Comment(0)
A
186

Does BroadcastReceiver.onReceive always run in the UI thread?

Yes.

Austronesian answered 15/4, 2011 at 12:41 Comment(21)
is this documented somewhere?Crystalcrystalline
@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(): goo.gl/8kPuHAustronesian
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!Crystalcrystalline
@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.Austronesian
@Austronesian Is is anything wrong if we start a thread inside the broadcastReceiver's onReceive() method. Will the thread break after onReceive() method returns?Streusel
@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.Austronesian
@Austronesian 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.Streusel
@Dharmendra: For registerReceiver(), the component that called registerReceiver() is really the one that "owns" the thread and is responsible for its cleanup.Austronesian
@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.Subdued
@Jules: Ah, very true -- my apologies.Austronesian
@Austronesian 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 .Matte
@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.Austronesian
@CommonsWare,Hi, please explain what if we are registering it on a separate thread .?Decosta
@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.Austronesian
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.Lasley
All four android component - (Activity, Service, BroadCastReceiver, ContentProvider) run on UI Thread by default. Its documented in the official Android Developer docsInflict
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?Guillen
@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).Austronesian
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...Guillen
@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.Austronesian
Reading what Looper is about (https://mcmap.net/q/73659/-what-is-the-purpose-of-looper-and-how-to-use-it) 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!!!Guillen
U
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.

Upanchor answered 13/4, 2012 at 11:34 Comment(1)
Yes. Sounds like your ability to change it via the Handler parameter is why they "hedged" their language in the docs.Sup
S
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.

Secondclass answered 27/11, 2013 at 16:39 Comment(1)
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.Poleax
I
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.

Immingle answered 30/12, 2013 at 2:8 Comment(2)
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?Seabury
@kidoher: Did you follow the code links here: https://mcmap.net/q/175636/-on-which-thread-does-onreceive-of-a-broacastreceiver-registered-with-localbroadcastmanager-run/281545 ?Immingle

© 2022 - 2024 — McMap. All rights reserved.