I am finishing my current activity using finish(). This is calling onPause automatically. I want to finish activity without onPause being called. My activity is running a song service so i want song to stop when app is in background but dont want it to stop when user goes from one activity into another in my app. I cant do stopService and startService in between activities because then there is a momentary lag in between the sounds.
A Service is an application component that can perform long-running operations in the background and does not provide a user interface
google docs
The background Service is agnostic of which Activity is running or any discontinuity between them.
The two types, "bound" and "started" are supposed to have different persistence characteristics but in practice (not stress testing) I find the bound Service does not clobbered for lack of system memory and is much easier to implement (despite tutorials claiming otherwise). It uses some IPC abstraction that appears as though it is being directly invoked from the Activity. The same can't be said of the "started" variety (unless it is also bound) which is IMO a closer approximation to the traditional service I would associate with web-servers (or anything that is already going to be experiencing not insignificant delays- such as due to network transmission).
(Lecture over) I see you are calling finish(). You need some way to shut down the Service from your Activity. Just make sure to branch aways from doing so when not intended. Code would be helpful but I can assure you this is how media players work.
Related
It seems Android in recent version have introduced multiple restrictions on running services in the Background, which of course it good news for battery life of our devices. My goal is to create an app which adheres to this by only running a service as long as the User is interacting with the app (which seems to be what they are aiming for). But it's anything but clear to me how you can implement this properly. My requirements are as follows:
The Service should be started as soon as any Activity becomes visible to the user.
The Service should stay uninterrupted in the running state while the user is interacting with the app (browsing between activities).
When the UI (regardless of what activity was active) is sent to the background, the Service should run for 2-3 seconds and then stop itself. The 2-3 seconds are needed for a clean shutdown of the service.
The service can be started via a Push message when the app is in the background (or closed), in order to handle incoming events at any time. The service then registers to the Remote Server, and checks for updates. If there are updates, a notification is given to the user. Then the service once more shuts back down after 2-3 seconds of inactivity.
To me, it seems a Bound Service is what is intended to be used. But it's not clear to me how my requirements will fit with the Bound Service model. Is there anyone who have any experience with this, who can point me in the right direction?
EDIT: The "Service" in this case is a Local, In-Process service, which is not intended to be accessed externally.
(This answer presumes a local, "in-process" Service, which is no doubt what you intend to use.)
For your use case, you actually use a combination of techniques to keep the Service running.
Use the "bound Service model" to keep the Service around while any one of your Activities are visible. It's simple enough; call bindService() in Activity.onStart(), and unbindService() in Activity.onStop(). If you're worried about the Service being destroyed in the brief moment of transition between two of your Activities, don't be; Android is smart enough to wait for the lifecycle changes of different application components to "settle" before it decides a Service is unreferenced/unneeded.
You should use the BIND_AUTO_CREATE flag for all your bindService() calls. Keep in mind that the Service isn't created immediately upon calling bindService(); it takes a few milliseconds, and you must be careful to return control to the framework, by returning from whatever lifecycle method (e.g., onStart()) you are currently in. Only then will you get a call to onServiceConnected().
You'll need to manually keep track of how many Activities are bound to your Service, in order to determine when to begin your 2-3 second cleanup logic. See this answer for a valid approach. Don't worry about the Service being destroyed synchronously during your last unbindService() call -- just as with bindService(), the actual lifecycle state change is "delayed."
Now the question is, how do you keep the Service alive for this extra 2-3 seconds, at this point (the point where you've determined the number of open Activities has dropped to 0)? Well, you can simply call startService(). You can even call it from a method in your Service subclass; as long as you have a valid Context available, it doesn't really matter. startService() indicates to the system that you want to keep the Service around, irrespective of how many Activities (or other clients) might be bound to it. In this case, the Service won't be restarted -- it's already running!
Once your cleanup is complete, you can call stopService() or, better yet, stopSelf(). That effectively cancels the startService() call, and tells the OS, "I'm done". Expect a call to Service.onDestroy() shortly thereafter.
Keep in mind that one of your Activities might pop up asynchronously, and re-bind to the Service, before cleanup completes. It is an edge case, but one that is easily handled. The Service will only be destroyed when both these conditions are true: 1.) No clients are binding/bound, and 2.) no un-cancelled calls to startService() exist.
Note that on Oreo and later, the system can be quite aggressive about killing apps with background Services. According to this doc, interacting with the user puts you on the whitelist for "several minutes", so I think 2-3 seconds is going to be OK. Similarly, if you're handling a "high-priority FCM message" (which is what I assume you mean by "push" message), you'll be placed on the whitelist, and allowed another few minutes in which to execute the Service (this time using the startService()/stopSelf() approach).
Just trying to clarify my understanding of how an IntentService is managed by the OS once terminating states have been reached. By terminating, I mean when the current activity is destroyed or the app process is killed, as per the following documentation:
https://developer.android.com/guide/components/activities/activity-lifecycle
Given the comment
Also, an IntentService isn't affected by most user interface lifecycle events, so it continues to run in circumstances that would shut down an AsyncTask
at https://developer.android.com/training/run-background-service/create-service;
I feel as if:
1) A started IntentService is unaffected by the activity lifecycle. Is this correct?
2) If (1) is true, will it continue to run indefinitely even after a terminating state is reached, up to some point that it either stops itself or the OS decides to stop it?
In my particular situation, I'm using an IntentService during app startup to query APIs, grab content, and then add a new (landing) Page to the Xamarin.Forms navigation stack (this would be equivalent to starting a new activity).
This leads me to my next question...
3) What happens if the app is already in a terminated state when it comes time to the IntentService creating a new Activity? Surely the Activity can't be added to the navigation stack as it no longer exists once the app is terminated?
Yes, a started IntentService is unaffected by the Activity Lifecycle. Actually, all Services outside of bound Services are unaffected by the Activity Lifecycle.
An IntentService will continue until it reaches completion of it's work, the application is destroyed, or if the System decides to kill the Service due to the changes in the Android 8.0 background Service rules.
Your use of terminated state is too broad... If the Application is already terminated, then nothing will happen because the IntentService would have been terminated already too. If it's the Activity that launched the IntentService that was terminated, then nothing happens, since by default, an IntentService has nothing to do with Activities, even if it's the one that started it.
For the last question, it really depends on how you choose to communicate the result of IntentService to an Activity.
If you're using a BroadcastReceiver, then nothing will happen because an IntentService will fire the broadcast without any problems, but the Activity won't be able to receive the results since it's terminated.
But if you're simply creating a new Activity, then you can simply use startActivity() with the result data added to the Intent. Though, I doubt the user will be happy to see an Activity suddenly open on the screen when they're no longer in your app. Starting a new Activity has nothing to do with a previous Activity, since any instance of a Context can start an Activity.
Honestly, based on your question, it sounds like you're very concerned with an IntentService and it's connection with the Activity that started it. If that's the case, you really shouldn't be using an IntentService, since that's not really it's purpose. It's not meant to have a connection with an Activity. It's simply meant to do work and finish.
Instead, a bound Service would be a better option since it has a direct connection with the Activity that started it.
I am looking for a bit of app design advice.
I have an app that connects to the Google Location Services and tracks location coordinates it receives. These are displayed as a path on the UI.
When the screen times out and goes blank then this Activity will, of course, shut down as per the normal Activity life cycle.
However - I atill want to record the co-ordinates coming back in each onLocationChanged event from Location Services, but, of course, the Activity has paused so it cannot do that.
I don't particularly want to prevent the screen from blanking in the Manifest (and thus the Activity would never pause). Though I believe it would still pause if, say, a phone call is received etc.
My solution would be to start an IntentService in one of the Activity pausing events (either onPause, onStop or onSaveInstanceState) to receive Location updates, and then when the Activity restarts, collect the data from the Service and close the Service down.
Would this be an efficient and correct way of achieving this, or is there some Android black art that I don't know about? If so, is IntentService the correct way to go about it (or should I use Service)?
Proberly a normal service that gets restarted by an alarmmanager is an better idea.
In order to tie up loose ends, I'll add my own answer to this now I have implemented something.
My solution in the end was not an IntentService. This was because I thought that the IntentService would consider its work to be the actual setting up of the LocationService and once that work had been completed then it would shut itself down rather than hang about waiting for LocationService 'pings'.
Therefore, I implemented a normal Service, but I bound it to the calling Activity. I also set up a callback to the Activity. This way when a 'ping' was received I could process it and pass back the data directly to the Activity. Also, the Service would remain alive as long as the binding was in place. I clear the binder when the Activity is destroyed.
This worked perfectly....HOWEVER
I then discovered that the reason that the LocationService 'pings' were not being handled in the Activity was bacause I was disconnecting the GoogleAPIClient when the Activity onStop was called. Having removed this, the Activity processed the 'pings'even in its stopped state, so no Service was required anyway.
Therefore the correct answer to this question is... Activity should continue processing in the background (unless it's destroyed for memory management purposes), so check you're not stopping stuff in your 'shutdown' handlers onPause onStop etc. Then you won't waste time writing services like I did!
I have a long running background task that I would like to start when the app launches and shutdown when the application shuts down. I'm already quite aware of the activity life cycle and what gets called when an activity gets created and destroyed.
I'm coming from an iOS background, and over there we have some calls that are made during application startup and shutdown. Is there something similar in the android world? I've searched a lot and all I'm finding are answers relating to an activity, not the entire application.
(Android is relatively new to me, so I may just not know the correct terminology to search for.)
EDIT:
I'll try an be a bit more specific. I have a background task that needs to be continuously running while the user is using the application. It will be streaming data from a server continuously while the application is active. It does not need to run when the application is in the background. It doesn't seem to make sense to me to tie the startup / shutdown of this background process to any one single activity since it may not be the same one activity that starts up when the application becomes active.
I am (possibly mistakenly) assuming that the OS takes care of starting / stopping background threads when the application resumes and pauses. If that is, in fact, the case, then all I really need to do is spin up the background task when the application first launches, i.e. when it is loaded into memory and becomes active for the first time that session.
It doesn't seem to make sense to me to tie the startup / shutdown of this background task to any one single activity since it may not be the same one activity that starts up when the application becomes active.
That's reasonable. It is somewhat difficult to implement, though.
I am (possibly mistakenly) assuming that the OS takes care of starting / stopping background threads when the application resumes and pauses.
You have it exactly backwards. Android pays not one whit of attention to any threads that you fork yourself, directly or via thin wrappers like AsyncTask.
In addition to that point of confusion, you appear to be equating "user switching to another app" with "app shutdown". Those may be the same thing in single-tasking operating systems. They are not the same thing in Windows, OS X, Linux, Android, etc.
So, what you seem to be seeking is having a background thread running doing this streaming work while your UI is in the foreground, and then stop when your UI is in the background. The problem is that there really isn't a straightforward way of accomplishing that in Android.
One close approximation would be to create and register a custom Application class, where you override onTrimMemory(), and stop your background work when you get to TRIM_MEMORY_UI_HIDDEN, TRIM_MEMORY_BACKGROUND, TRIM_MEMORY_MODERATE, or TRIM_MEMORY_COMPLETE -- whichever of those that you encounter first. If, when one of those arrives, you determine that your streaming thread is still outstanding, shut it down.
In terms of startup, you could use onCreate() on that same Application singleton. The problem is that this will be called on any process creation, which may include scenarios in which you do not have UI (e.g., you are responding to some system broadcast, like ACTION_BOOT_COMPLETED), or possibly your process is going to parts of your UI that do not depend on the streaming. If you have none of those scenarios, then onCreate() in Application would be fine. Otherwise, kick off the streaming in onCreate() of whatever activities need it.
While normally we manage long-running threads with a Service, that is for cases where we explicitly want the thread to continue after our UI is in the background. Since you do not want that, you could skip the service.
It depends on what you want to do exactly. When you're just interested in the app starting for the first time you could #Override onCreate().
Or maybe you want to use onResume() as this will get called whenever a user brings the app to the foreground.
But this really depends on what exactly your background task is doing and what you want to do with it, to get an exact answer you need to provide more details.
Here is an overview for the actiity life cycle that should help you:
You can extend the default Application class and implement it's onCreate() method to detect when the app is launched. There is no corresponding method for when the app gets closed though.
Do not forget to specify it in the Manifest file.
In Android the application isn't shut down unless the system runs low on memory. You won't get a warning about that, it will just call your Service's onDestroy lifecycle method. If you want to do it when the Activity is visible on screen, use onStart and onStop. If you want to do it when the Activity is resident in memory, use onCreate and onDestroy.
I have a Service, which is foreground. It is locally bound to one (or more) activity, so the activity and the service runs in the same process. There might be some time during which the activity is not displayed (typical music player use case).
If service and activity are in the same process, the memory for the activity can't be repossessed by operating system, unless the service too is terminated? The answer seems yes to me, according to this article
If the last is true, should I create two separate process:
To be nice to the system/other apps?
to be more confident my service will not be killed?
Or, it is not a big deal to have the activity sticking around together with the service?
I have a Service, which is foreground. It is locally bound to one (or more) activity, so the activity and the service runs in the same process. There might be some time during which the activity is not displayed (typical music player use case).
A "typical music player use case" would not use bindService() IMHO. A foreground service would not use bindService() IMHO. At minimum, in addition to bindService() for activity->service communication, you would need startService(), so that after you unbindService() (e.g., user presses BACK), the service can stay running.
If service and activity are in the same process, the memory for the activity can't be repossessed by operating system, unless the service too is terminated?
The memory for the activity is never "repossessed by the operating system", except by terminating your entire process. Unfortunately, this is not entirely clear from the documentation.
If the user pressed BACK to exit the activity, or you otherwise call finish() on the activity, the activity should be garbage-collected, assuming nothing is causing it to hang around (e.g., referred to by a static data member).
should I create two separate process
Absolutely not.