How does BroadcastReceiver work belong to app state? - android

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.

Related

How does Context-registered receivers work

My confusion is that -
If a Context-registered receiver receives broadcasts as long as their registering context is valid- then how does an app get notified if it's not launched.
In Manifest-declared receivers the receiver app would have got started by the system, so how does it work for Context-registered receiver ?
One way or another, you need context to receive Broadcasts in onReceive method of BroadcastReceiver
For Manifest-registered receivers, if application is not running then system may start the app and deliver the broadcast if the app is not currently running. After onReceive(), the system can kill the process at any time to reclaim memory. The passed context in this case is:
Context class: android.app.ReceiverRestrictedContext
Application context: android.app.Application
For Context-registered receivers, it is clearly stated in Broadcasts | Android Developers:
Context-registered receivers 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. If you register with the Application context, you receive broadcasts as long as the app is running.
If you declare a BroadcastReceiver in the manifest, Android will create an instance of that BroadcastReceiver and call onReceive() when it wants to dispatch a broadcast Intent to that receiver (based on the specified <intent-filter> conditions.

How to receive message when activity is inactive?

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.

Lifetime of BroadcastReceiver with regard to Android O changes

If I declare a BroadcastReceiver via the mainfest file for a system broadcast (let's say for example ACTION_POWER_DISCONNECTED) the the system will call it every time the specific broadcast is send so the lifetime of the BroadcastReceiver is unrestricted.
But there are also broadcasts which can not be registered via the manifest file. For these broadcasts we have to call context.registerReceiver with a corresponding IntentFilter. Let's say I create a BroadcastReceiver for BOOT_COMPLETED and call context.registerReceiver from it and never call unregisterReceiver does this receiver also lives forever (until the phone is rebooted)?
Apps that target Android O can no longer register broadcast receivers for implicit broadcasts in their manifest. An implicit broadcast is a broadcast that does not target that app specifically.
If my conjecture from above is right this would be an easy workaround for the system change (of course you shouldn't do it this way but it would be possible). So does a BroadcastReceiver which is registered after a BOOT_COMPLETED broadcast have the same lifetime (stays until the next reboot) as a BroadcastReceiver which is automatically registered via the manifest?
Let's say I create a BroadcastReceiver for BOOT_COMPLETED and call context.registerReceiver from it and never call unregisterReceiver does this receiver also lives forever (until the phone is rebooted)?
First, BOOT_COMPLETED is one of those actions, that still will behave like they were before, meaning restriction introduced in "O" do not concern to that action.
As soon as the process of your app is killed by the system or as soon as system clears your app's memory (as a result of low-memory of device), your broadcast registration will be lost. Otherwise I cannot see how this limitation will result in a better battery experience.
So does a BroadcastReceiver which is registered after a BOOT_COMPLETED broadcast have the same lifetime (stays until the next reboot) as a BroadcastReceiver which is automatically registered via the manifest?
If above mentioned cases are not met, i.e. the process of your app stays alive and app is not cleared from memory because of memory shortage - then yes. Once entered into cached state (the state with no active Android component) the registration will be lost again.
This short video by Nasir Khan will be helpful.

Android: will the dynamically registered broadcast receiver be activated if the app process has been killed

As I know, statically registered (via manifest) broadcast receiver will be activated when the broadcast is fired, it doesn't require the app process is running. But what about the dynamically registered one?
AFAIK, You can make your Broadcast Receiver can run in background even your application is closed or destroyed or killed.
If you want to do above one , you should not be registering it via registerReceiver(). Register it in the manifest via a element instead. Then, it is available whether or not your application is running.
One more option if you want the broadcast receiver to killed or stopped whenever your application is closed or destroyed or killed.
you should call/invoke registerReceiver() method in your onCreate and You should call/invoke unregisterReceiver() in onResume() or in onpause() methods as per your need you can use this.
One of the differences between BroadcastReceiver that declared in AndroidManifest.xml and the one that registered with Context.registerReceiver() is that first one is instantiated by the Android system, when the second one - by the application code. When application process is terminated, all it's data (including all objects and jvm itself) is destroyed. So the only way to handle broadcast Intent for your receiver is to start new application process, instantiate new YourBroadcastReceiver and call its onReceive() method (and this is what it does for receivers, declared in manifest). But in case of receiver that was dynamically registered with registerReceiver() the system gets just some receiver instance, but not a mechanism for its creation. Furthermore, if for example your receiver class is non-static inner class then there is no reasonable way to instantiate it by the external (system) code because the system could not know, in which state the external object (and application) should be, to receiver worked properly. Also constructor could have arguments.
So if the process is terminated, your dynamically registered BroadcastReceiver will never called until you register new one in a new process.
As the android documentation says:
When you are defining broadcast receiver in your app manifest(Manifest-declared receivers),
The system package manager registers the receiver when the app is installed. The receiver then becomes a separate entry point into your app which means that the system can start the app and deliver the broadcast if the app is not currently running.
But when you are dynamically registering the broadcast receiver(Context-registered receivers),
Context-registered receivers 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. If you register with the Application context, you receive broadcasts as long as the app is running.
So your dynamically registered broadcast receiver will not be activated when your application is killed.

How to release resources for a broadcast receiver after it has been used?

I have been trying to work out how to clear a broadcast receiver after it has been used. My app currently has the broadcast receiver registered within the Android Manifest and then I am calling it using an intent , to a PendingIntent and then from there I use an AlarmManager , this then triggers the Broadcast receiver at the specified time,
However I feel that when the time occurs and the broadcast receiver has been processed, it is then left in memory unused.
I have read other posts and articles about unregistering the broadcast receiver from the activity it came from, however the activity it starts from, needs to have the ability to be closed without effecting the broadcast receiver, so if I unregister it at the onPause() part of the activity, surely this will end the broadcast receiver before it has started?
Any help would be appreciated.
Let the system handle it. It will be garbage collected as needed and often is quickly. In addition, the BroadcastReceiver javadoc states that it will be aggressively killed.

Categories

Resources