If an activity wants to bind to a started foreground service, should it bind in onCreate() and unbind in onDestroy() or bind in onResume() and unbind in onPause()?
The content of the activity is dependent on data stored within the service, so it must be connected to display correctly. Is there any advantage to the latter option?
Since setting up the ServiceConnection takes some time, binding to the Service in onResume() may be way too late for your app to work smoothly. In addition to that, onPause() will also be called e.g. when you show an AlertDialog, so unbinding there means you'd have to "re-bind" as soon as the dialog is dismissed and - again - wait for the ServiceConnection to be up and running.
The documentation on Bound Services states
You usually pair the binding and unbinding during matching bring-up
and tear-down moments of the client's lifecycle, as described in the
following examples:
If you need to interact with the service only while your activity is visible, you should bind during onStart() and unbind during
onStop().
If you want your activity to receive responses even while it is stopped in the background, then you can bind during onCreate() and
unbind during onDestroy(). Beware that this implies that your activity
needs to use the service the entire time it's running (even in the
background), so if the service is in another process, then you
increase the weight of the process and it becomes more likely that the
system will kill it.
So in your case you can use onStart()/ onStop()
Related
Can I safely stop a Service in my main Activity's onDestroy method? I know that onDestroy is not guaranteed to be called, but I also do want to keep my Service running until the app is destroyed.
I'm thinking that maybe in all situations where the activity is destroyed, the service would also be destroyed?
You can stop a service in the onDestroy of an activity, but to do it successfully requires either:
Running a Service in the Foreground
A foreground service is a service that's considered to be something
the user is actively aware of and thus not a candidate for the system
to kill when low on memory. A foreground service must provide a
notification for the status bar, which is placed under the "Ongoing"
heading, which means that the notification cannot be dismissed unless
the service is either stopped or removed from the foreground.
For example, a music player that plays music from a service should be
set to run in the foreground, because the user is explicitly aware of
its operation. The notification in the status bar might indicate the
current song and allow the user to launch an activity to interact with
the music player.
or Managing Bound Services
A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves another application component and does not run in the background indefinitely
In all your activities, manage any resources you have created within that activity and with a null check, close them down. Like you have in your service class. If you want to override the parent onDestroy, place your custom code before super.onDestroy.
There's more detail about this here.
but I also do want to keep my Service running until the app is destroyed.
The activity can remain on the stack in the stopped state and will not be destroyed until more memory is needed. This means that there is no fixed time that the service will continue to run until the activity is destroyed.
Activity Lifecycle
If an activity is completely obscured by another activity, it is stopped. It still retains all state and member information, however, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere.
The entire lifetime of an activity happens between the first call to onCreate(Bundle) through to a single final call to onDestroy(). An activity will do all setup of "global" state in onCreate(), and release all remaining resources in onDestroy(). For example, if it has a thread running in the background to download data from the network, it may create that thread in onCreate() and then stop the thread in onDestroy().
To ensure that all your resources are cleaned up, you could either call finish() on the activity, or end the service in the onStop() method or use a timer in the onStop(), that will end the service or destroy the activity after x time.
The problem with calling finish() is that if the use navigates back to the activity quickly, it needs to be recreated. The problem with using stop() is if the activity is restarted the service will need to be restarted. So a timer could be a way to keep the activities natural state preserved to allow user navigation, but it would need to be stopped if the activity resumes in onResume().
For protected void onDestroy ()
Perform any final cleanup before an activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it, or because the system is temporarily destroying this instance of the activity to save space. You can distinguish between these two scenarios with the isFinishing() method.
Yes it is safe to do it in onDestroy. Because before killing your activity background service or forground service that is bound to component will get killed by system as priority for service running in background is lesser then component you are interacting with.
Suppose that Activity A starts Service S and binds to Service S.
What will happen to S when A is destroyed?
How can I recreate another Activity that binds to S? The sample code in http://developer.android.com/guide/components/bound-services.html unbind the service in onStop(). I think if I open the app again, a new process is created for another instance of A and S. But I want the new activity to get data from the old service.
What will happen to S when A is destroyed?
If A is the only Activity bound to S and you didn't start the Service via startService(Intent), S will be destroyed. That's because a Service will be alive till the last bound Activity unbounds from the Service. This is documented here.
How can I recreate another Activity that binds to S?
If A is bound and you switch to Activity B via Intent, the Service will be destroyed and recreated when B binds to it.
If you want the Service to be alive even if no Activity is bound to it, you have to call the Servie with startService(Intent). Now it will be around if you explicitly stop it or system means it's time to destroy it. If you don't want this behavior, persist your data and access it at given time.
I think if I open the app again, a new process is created for another instance of A and S
The process remains the same till the process is killed from the system or if you kill the process, which is not recommanded.
Edit:
Only the bound service lifecycle depends on Activities. If you want a stand alone one use startService(). This way it's independent from Activities and runs in background as long as the process of the App is up or you explicitly stop the Service with stopService() / stopSelf(). You could even have a Service in a own App and use IPC to communicate between Apps. It's all a matter of the use case.
As you can see the configuration of a Service is very flexible and you have to decide which fits best for your App.
If You start service through startService() it will keep remaining after Activity finishes.
If You start service through bindService() it will live until last Activity unbounds from it.
Also if service is already started and you call startService() no new instance of service will be created, but in living service method onStartCommand() will be executed.
Almost same when you bind to living service, methon onBind() will be executed.
Android provides the Service class, which can be useful for background or non-UI operations.
I have a question about Services' lifecycle.
I know that bound services have the lifecycle like following:
Some component starts the Service via bindService() -> onCreate()
onBind()
process
The binding component calls unbindService() -> onUnbind()
onDestroy()
My question is:
Activities usually call unbindService() at onStop().
However, the Activity can be killed without calling onStop() - I mean, when the system memory is low, the only method that must be called is onPause(). onStop() is after onPause(). Before calling onStop(), the Activity can be destroyed.
In this case, the Service didn't get unbindService(), so the Service is still running. Is this right?
Of course, this rarely happens because Services are background by default. (Services are more likely to be killed by system on low memory.) However, a "Foreground" Service has higher priority than the "onPause()ed activity." according to http://developer.android.com/guide/components/processes-and-threads.html . In this case, the binding activity will be killed first.
If this thing happens, the Service does not end? If memory is not low anymore, then the Activity will be created again, but will call bindService() again since it is a new instance. Also, the Activity even may not restart. Isn't this right? What can I do in this case?
The Service is killed, but if you have 'return START_STICKY' being returned from the onStartCommand(...) [AND you are starting the service using 'startService(intent)'], the service will start back up again. The Service will start back up even if the Activity is not opened again.
I have run this example - the BoundedAudioService example and tested by killing the activity - the service restarts itself. (By restart I mean, the onStartCommand(...) of the service is called again)
A bound service typically lives only while it serves another application component and does not run in the background indefinitely.
I have a remote service, and I want to use the service to check some conditions in onPrepareOptionsMenu. But sometimes I got "binder null" exception when I back from other activities. I set binder to null in onServiceDisconnected.
My question:
Does onServiceDisconnected be called after activity onStop?
Is it better to bindService in onStart instead of onCreate?
Could you please explain simply the difference of local service and the remote service?
1) No. onServiceDisconnected() only gets called when the Service terminates unexpectedly, like when the process hosting the Service crashes. It will not be called when you unbind from the Service yourself. From the documentation:
Called when a connection to the Service has been lost. This typically
happens when the process hosting the service has crashed or been
killed. This does not remove the ServiceConnection itself -- this
binding to the service will remain active, and you will receive a call
to onServiceConnected(ComponentName, IBinder) when the Service is next
running.
2) Generally, if you don't need to be connected to the Service while your Activity is stopped, then yes, binding in onStart() and unbinding in onStop() is the right way to go. The idea here is that you won't be wasting resources when your Activity is in the background. However, the documentation for bound services state that binding in onCreate() and unbinding in onDestroy() is OK too in some cases.
3) A local Service implies that the Service is in the same process as the consumer. A remote service is a Service that is in a different process.
I want to know what is the best place in an Activity to bind to a service?
I saw examples doing it in onResume() and also in onCreate(). I was asking myself if it is not a problem putting it into onCreate(), because in onPause() I will do a unbind to the service, so I don't get a serviceConnectionLeak, if I leave the activity. Now if I press the Home Button and then switch to the Home Screen, the Activity will unbind from the service, when I go back to the Activity from the Task Manager, then onCreate() will not be called and if the code is trying to access a function from the service I will get a NullPointerException. If I bind and unbind only in onResume() and onPause() I don't have this problem. Am i right?
I would generally recommend doing this in either onCreate()/onDestroy() or onStart()/onStop(), depending on the semantics that you want:
If your Activity wants to be interacting with the Service the entire time it is running (for example maybe it can retrieve some data from a network for you and will return the data when ready and you want to allow this to happen while in the background so if the user returns you will have the data ready), then onCreate()/onDestroy() is probably appropriate. Note that the semantics here is that the entire time your Activity is running it needs the Service, so if this Service is running in another process then you have increased the weight of it and made it more likely for it to be killed while in the background.
If your Activity is only interested in working with the Service while visible, then onStart()/onStop() is appropriate. This means your Activity will unbind from the Service when the user leaves it (and it is no longer visible) and connect back up the next time the return and it is re-started and resumed.
I generally wouldn't recommend doing bind/unbind in onResume() and onPause(). These generally won't decrease significantly the amount you use the Service (and thus your overhead), and in fact, because a pause and resume happens at every activity transition, this is a code path you want to keep as lightweight as possible. Doing it here can have other unexpected negative consequences: for example if multiple Activitys in your app bind to the same Service, when there is a transition between two of those activities the Service may also get destroyed and recreated as the current Activity is paused before the next one is resumed.
Also these pairs (onCreate()/onDestroy(), onStart()/onStop(), onPause()/onResume()) are intended to be the proper pairs for acquiring and then releasing resources (such as binding to Services, registering receivers, etc) to ensure that they are correctly acquired prior to being needed and released (and not leaked) when no longer needed.
What you say is correct. In most cases you will want to register in onResume() and unregister in onPause(). If you use onCreate() and on onDestroy() you will still be registering for updates when you are paused, which is being a bad citizen. If you register in onCreate() and unregister in onPause(), when you resume the task the registration will be gone, which is almost certainly not what you want.