I'm using BroadcastReceiver in activity to receive message from others services. It works well, but the problem is that
When my app goes to the background, the BroadcastReceiver will be unregister from the activity. so the messages which are received before the activity go to front will be lost.
How to handle the case?
Scenario A: Only The Activity
If you only need to receive the broadcast when you have an activity in the foreground, have the activity register the BroadcastReceiver using registerReceiver(). As #MisterSquonk indicated, you would register the receiver in onResume() and unregister it in onPause().
Scenario B: Activity If In Foreground, Else Other; Ordered Broadcast
If you want the foreground activity to handle the broadcast, but you want something else to happen if that activity is not in the foreground (e.g., raise a Notification), and the broadcast is an ordered broadcast (e.g., incoming SMS), then you would still use the Scenario A solution, but with a higher-priority IntentFilter (see setPriority()). In addition, you would register a BroadcastReceiver via a element in the manifest, with a lower-priority for the same broadcast. In the activity's BroadcastReceiver, call abortBroadcast() to consume the event and prevent it from reaching your manifest-registered BroadcastReceiver.
Scenario C: Activity If In Foreground, Else Other; Regular Broadcast
If Scenario B almost fits, but the broadcast you are listening for is not an ordered broadcast, you will need to start with Scenario B. However, have the broadcast that both receivers have in their respective filters be one of your own, using a private action string as #MisterSquonk suggested. In addition, have another BroadcastReceiver registered in the manifest, whose is for the real broadcast you're listening for. That receiver would simply call sendOrderedBroadcast() to send out the ordered broadcast that the other receivers are listening on.
Scenario D: Activity Regardless of Foreground
If some activity of yours needs to know about the broadcast, and it does not matter whether or not it is in the foreground, you need to rethink what you mean by that. Usually, this really means that the broadcast affects your data model in some way, in which case your concern should not be to let the activities know, but rather to update your data model, and use your already-existing "let the activities know about the data model change" logic handle the rest.
If, however, you are convinced that this is not part of your data model, you can implement Scenario B or Scenario C, plus stick some information in a static data member. Your activities can examine that static data member in onResume() to pick up the information about the broadcast when they return to the foreground.
If you're thinking "but, what if my process is terminated between the broadcast and the other activity coming to the foreground?", then your broadcast really is updating your data model, per the opening paragraph of this scenario.
If you're thinking "but, I want to update an activity that is doing work in the background", then the activity in question is broken. Activities should never be doing work in the background. That work should be delegated to some form of service, and there's a whole related set of scenarios for getting a broadcast to the service.
If you declare the BroadcastReceiver in the Manifest, it will always be active and be called even if the application is closed.
Related
My question is about behavior of Receivers when app is 'Died' - does receivers die also with it, or they are still working in memory?
My problem is about such situation - I can't listen action 'App is destroyed' and carefully do 'unregisterReciever'. So i want to know - what happens with receivers in memory belong to app state.
PS - approachs like doing unregister in 'onstop' of Activity doesn't fit to my situation.
Well ! The behaviour of whether the receiver will die/destroy (In terms of execution) depends upon the type of receiver you are registering. If you are registering your BroadcastReceiver in app Manifest Manifest-declared receivers then after the app is closed BroadcastReceivers don't die as Official documentation says.
The system creates a new BroadcastReceiver component object to handle
each broadcast that it receives. This object is valid only for the
duration of the call to onReceive(Context, Intent). Once your code
returns from this method, the system considers the component no longer
active.
If you declare a broadcast receiver in your manifest, the system
launches your app (if the app is not already running) when the
broadcast is sent.
The Other type of BroadcastRecievers is Context-registered receivers.
Context-registered receivers are those receivers that:
receive broadcasts as long as their registering context is valid. For
an example, if you register within an Activity context, you receive
broadcasts as long as the activity is not destroyed
in that case when the context of the linked component is destroyed then BroadcastReciever will also be destroyed.
I'm trying to implement an app that times how long my phone screen is on throughout the day using a broadcast receiver.
I'm declaring Action_Screen_Off/Action_Screen_On in my broadcast receiver since I can't declare it in my manifest, and I've been debating on the best way to handle storing the amount of time that my screen was on.
Since I can't declare it in the manifest, Should I declare the broadcast receiver inside of the onCreate in my activity? My worry with that is, if my understanding is correct, is that my receiver would then be tied to the lifecycle of the activity and I would only be able to store the on/off times whenever the activity is active.
The whole point of the app is that it's working in the background, and then displaying graphs of usage once an activity is in the foreground.
This led me to think that a Service might be the best bet the handle the Broadcast receiver, but Google seems to now be recommending that we don't use background services, only bounded and foreground services.
How can I make sure that my app is receiving the on/off intents, without the activity that declares the receiver being in the foreground, and the receiver not depending on the lifecycle of that activity?
You need a background Service for this functionality. Your Service doesn't need to actually do anything, but it needs to be active all the time so that you have something to anchor your BroadcastReceiver to. In onCreate() of your Service, create an instance of the BroadcastReceiver and register for the screen on/off events. Make sure that you return START_STICKY from your onStartCommand() in your Service. This will ensure that the Service is always active, and Android will restart the Service if it kills off your process (for whatever reason). The BroadcastReceiver can just write the timestamps of the on/off events to a file, SQLite database or SharedPreferences and your Activity can then read this data and show the graphs or whatever.
Let's say I have an Activity. In its onCreate lifecycle callback I create a BroadcastReceiver object by implementing it as an anonymous class and put some code inside its onReceive callback that requires Activity's Context to show a Toast message when it gets called. In Activity's onResume callback I register that BroadcastReceiver and in onPause I unregister it, because it contains code that requires Activity's Context, and it might not be available if Activity is going through the destruction procedure, i.e. orientation change. This means that if something, i.e. IntentService broadcasts an Intent for that BroadcastReceiver while it's unregistered (no matter how short, but it still can happen), the Intent will never get delivered and proper actions that handle it will never happen. So the user might miss some important information (message informing about a succesfull registration, warning that something went wrong etc.) Am I right? Is it true that such scenario may happen? How to prevent it? How to make sure that the BroadcastReceiver will receive the broadcast no matter when some part of the application fires it?
Create MyBroadcastReceiver extending BroadcastReceiver (of course :D) and register that in the manifest with the appropriate intent filter action. Then in onReceive() you'll have access to Application's Context. Keep in mind that onReceive() will be triggered even if your app is closed (if your action is Intent.ACTION_SCREEN_OFF for example).
It depends on what you're trying to do in that receiver...also have a look at EventBus https://github.com/greenrobot/EventBus if you have to send events in your app.
I am trying to create my first Android app. I would like a main-thread Activity (in my case: an ActionBarActivity) to receive notification of an event from a background Activity (in my case: an IntentService). I've read that using broadcasts should be the best way to do this.
To register a Broadcast Receiver for listening to broadcasts sent from the background activity, I am using the following code inside the main-thread activity:
// Register broadcast receiver
LocalBroadcastManager bManager = LocalBroadcastManager.getInstance(this);
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.me.myBroadcast");
bManager.registerReceiver(bReceiver, intentFilter);
I tried putting this in the onCreate() method of my main-thread activity, but I quickly discovered that every time I restart the activity (e.g. closing the app and re-opening it), it seems to create "duplicate" broadcast receivers, which then trigger the Broadcast Receiver's onReceive() method multiple times whenever a single broadcast is sent. This is causing problems.
So I created a SharedPreferences file to save a boolean which remembers whether or not I have already created a Broadcast Receiver, so as to avoid creating duplicates. This works exactly as hoped, until I restart the device of course, after which the Broadcast Receiver is destroyed, and the app doesn't create a new one because the SharedPreferences boolean says it already has one.
I'm guessing I could patch this issue by setting up a new broadcast receiver to listen for a device reboot, which resets the SharedPreferences boolean, but I have this nagging feeling that I am overcomplicating things massively. What am I missing? Thanks for any help offered!!
To answer your question, you can ignore sharedprefs and register the broadcast receiver in onResume and unregister the receiver in onPause. This method is well described in Reporting Work Status(1) android doc. Note that, this way, you will get status updates only if Activity is in foreground. Use appropriate life cycle methods depending on your needs.
To report status back to foreground activity from service, my preference would have been ResultReceiver(2) class which feels natural compared to a broadcast. Also, if you need to report multiple status messages back, it will be clearer with statusCode param in onReceiveResult method of ResultReceiver class.
I need to be able to have a service "tell" a BroadcastReceiver to do some work, and then wait until that work is done, and once it's finished, the BroadcastReceiver needs to send the result back to the service. And at that point, the service can continue execution.
So, "sending" the work from the service to the BroadcastReceiver is easy -- I just send a broadcast with the intent using extras for the work that needs to be done. But I don't know how to have the BroadcastReceiver then send the results back to the service. What's the best way to do this?
Edit:
I should have mentioned that the service in question is actually a contact sync adapter service. I'm not sure if that makes a difference, but maybe it does. Some of the work can't be done in the scope of the sync adapter, and that's why I'm offloading it to be done by the broadcastreceiver.
Register a Second inline Broadcast Receiver from the Service just to receive the results from the First Broadcast receiver. Pass the data via Intent. In the Second Broadcast receivers onReceive() do whatever you want.
Unregister the Second Broadcast Receiver in onDestroy of the Service.