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.
Related
Unlike dynamically registered Broadcast Receivers, the ones registered in the manifest are able to respond to events even after the activity or even the app that created it has been closed.
So, my questions are:
Every time there is an event, is an instance of every broadcast receiver registered for that event created? (even if the app is not running anymore)
In that case, isnĀ“t it a performance issue? Potentially every time there is an event the system might have to recreate a bunch of old broadcast receivers just to handle that event.
I know the developer should be responsible, but since potentially this is possible to do, why does the system allow this outside the lifecycle of an app?
As of Android 8 implicit broadcasts no longer work except for those ones.
So unless the package is explicitly set on the intent to have your package, your package will not receive the broadcast. The link above explains in more details.
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.
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.
I have built an application which implements a number of broadcast receivers and registers them within a service based on user settings. The service is bound to an activity which calls some of its methods.
When a broadcast receiver is called it starts the service (or calls onstart of the service if it is already running) and passes it a string telling the service what to do. My problem is when the activity is destroyed (back button) the service is also destroyed which in turn kills the broadcast receivers.
I know I can register the receivers in the manifest which would mean doing a check when they are called to see if the user has selected that option. However one of the receivers critical to the application is 'android.intent.action.HEADSET_PLUG' which can only be registered programatically.
So I guess my question is, is there a way to keep this broadcast receiver active when the service is destroyed?
If not can anyone see a workaround for this issue?
Thanks,
Rob
My problem is when the activity is killed the service is killed which in turn kills the broadcast receivers.
If by "killed" you mean the user terminated your app with a task killer or "Force Stop" in the Settings app, then "killed" is the appropriate verb. However, your whole process is "killed" -- it does not follow the chain of events that you describe here.
If by "killed" you mean the user exited your activity via the BACK button, that is because you elected to bind to the service, rather than start it. If you want the service to continue executing past the lifetime of the activity, you must use startService(), and ensure that there is some path by which the user can indicate that they no longer want this service, so you know when to call stopService().
So I guess my question is, is there a way to keep this broadcast receiver active when the service is killed?
No.
If not can anyone see a workaround for this issue?
Start your service, instead of (or possibly in addition to) binding to the service.
I am planning to register for few events in my broadcast receiver that is registered in java code (not manifest). I need to listen to these events for the entire lifetime of the application. In order to receive the events for whole application lifetime, do I need to hold the partial wake lock for entire application lifetime (As I am not registering in manifest) ? Please help.
If you have an Activity or a Service running and you called registerReceiver() in either one, then you can only expect to continue receiving the broadcasts while the CPU is on.
If you want to receive even while the user is not using the device, then yes, you need to use a partial wakelock.