Stackoveflow!
I have an application with sticky background service and visible part, consisted of several activities.
I need to track start and stop of visible part (all activities).
For example:
When user starts MainActivity, Service receives LocalBroadcast that tells it to start something.
When user rotates screen, Service must not receive anything.
When user goes to SecondActivity, Service again must not receive anything.
When user closes ALL ACTIVITIES, Service gets LocalBroadcast telling it to stop something.
If I use Activity. onCreate and onDestroy, or onStart and onStop, I get events related to lifecycle of single activity. Also I get events related to screen rotation.
I also cannot use Application. onCreate or onTerminate, as they will not trigger because of service running in the background.
I need to track real start and stop of entire application except service.
See: http://developer.android.com/guide/components/bound-services.html
When the last client unbinds from the service, the system destroys
the service (unless the service was also started by startService()).
So each Activity should bind() to the service, in onCreate, and unbind() in onStop/onDestroy
Now to fix the problem with the orientation changes, you can check for isFinishing in the onStop/onDestory callback
(see: How to distinguish between orientation change and leaving application android)
and also put some flag in onSaveInstanceState callback, so that in the following onCreate you can check for the existence of that flag, and act accordingly (refresh the binding, or avoid calling bind() again)
Related
My activity binds to a service in onResume and unbinds from in onPause so it can use the service as long as it is active.
Now I want to avoid this (un)binding if the activity is recreated only because of an orientation change (display rotation). Keeping the connection object alive (instead of creating a new one) is possible using onRetainCustomNonConfigurationInstance().
But I don't see a way to know when I can skip unbinding in onPause and later re-binding in onResume. What can I do to handle this special case?
Another thing I'm thinking about is, is there a way to get told when the app goes active or inactive? Then I could keep the service alive for all my activities and unbind from the service only if the app gets destroyed or put in the background. (compared to bind to the service for each activity, which I have to do to in order to unbind the service correctly when an activity is left and no other one is coming)
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.
I have a doubt that if i start a periodic service using alarm manager and start the service from the onCreate method of an activity. How can i prevent the service from triggering multiple times if that activity is launched again and again.
Assuming that you are creating a Normal Service (and not an IntentService), as per the Android Service documentation, when app invokes startService call, service will be instantiated and started (creating a process for it if needed).
Also, if it is running then it remains running.
So, to put it in simple terms,
Life cycle of "Started" service is independent of the life cycle of
Activity which has started this service. This is true irrespective
weather both are running in same process or different processes
So even though your Activity may be getting created multiple times, and if Service you created earlier is still running, then service object that already exists will be reused.
However, if there is a call to startService() from onCreate() of an Activity, this will invoke each time onStartCommand().
Hence, you need to ensure that you have a appropriate code/logic to handle multiple invocations of onStartCommand()
As far as I understood you must do something in either onCreate/onStart and onStop or onResume and onPaused. By do something I mean, in onCreate create what you need, alarm manager, etc then in onStart you can start the service and in onStop you stop the service or unBind from it, in case you want a foreground service. or in onResume or onStop.
Take a look here:
https://github.com/toaderandrei/live_tracking/blob/master/app/src/main/java/com/ant/track/activities/ServiceConnectActivity.java.
It is a tracking app that is based on MyTracks app from google.
I would like to have my service perform something when the user presses Home or Back.
I'm not looking to override or block the normal behavior of these buttons, just get notified about them.
I need to get notify even when the activity that started the service is stopped.
Working with platform 17-19.
Is there any way?
Can it be done by intent-filter or broadcast receivers??
Thanks
Only Activities (and Fragments) will get these callbacks (onPause, onStop etc.). If your Activity is running, it can notify the service, but once it's in the background there is no way to do this.
If the service is on you can use a broadcast by hooking into onPause or on onStop methods in the activity. if the service is not on I think you have to start it, do something, then end.
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.