How to receive and process location changes when an Activity is paused - android

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!

Related

How is a running IntentService managed after the app process is killed

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.

Long running operation inside onEvent of FileObserver

I have an activity that contains an Instance of FileObserver. I start watching in onCreate and stop watching in onDestroy of the activity. So what happens if onEvent is doing some operation and the activity is destroyed (user presses back button)? Does my onEvent continue to finish what it was doing? Basically I am wondering whether onEvent should start a service or handle its business itself.
Does my onEvent continue to finish what it was doing?
At least briefly, yes. FileObserver is not tied to a specific component's lifecycle, like that of an Activity.
However, once your app is no longer in the foreground, your process can be terminated at any point, to free up system RAM for other apps. Android is not going to pay any attention to your FileObserver and its onEvent() processing when this occurs, by default.
If you expect the work to happen quickly — say, under a second — you should be able to keep it where it is.
If, however, the sort of work that you are doing is more substantial, I would consider having a service do the work. Per our prior discussion, while the FileObserver should not be in an IntentService, the work triggered by the FileObserver could be. onEvent() would call startService() to tell the service to go do the work. Services are a signal to the OS that you are actively doing work on behalf of the user, and so your process is more likely to hang around for a bit longer.
Unless the Application is stopped the code in your onEvent will continue to run.
FileObserver.onEvent documentation
This method is invoked on a special FileObserver thread. It runs independently of any threads, so take care to use appropriate synchronization! Consider using post(Runnable) to shift event handling work to the main thread to avoid concurrency problems.
So the only think you need to be concerned with is what exactly you are doing in onEvent. For instance if you are updating UI or interacting with the Activity / Fragment in your onEvent method then this could cause a crash if the Activity goes away.
With that in mind a service will certainly increase the odds that the application does not terminate while you are performing your work.
Service documentation
The Android system will force-stop a service only when memory is low and it must recover system resources for the activity that has user focus. If the service is bound to an activity that has user focus, then it's less likely to be killed, and if the service is declared to run in the foreground (discussed later), then it will almost never be killed. Otherwise, if the service was started and is long-running, then the system will lower its position in the list of background tasks over time and the service will become highly susceptible to killing—if your service is started, then you must design it to gracefully handle restarts by the system. If the system kills your service, it restarts it as soon as resources become available again...
So the bottom line is that a service is more likely to keep your application alive. Event more likely if you call startForeground but in this case you need to be willing to show a notification to the user.

Finishing activity without onPause called

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.

Dealing with paused or stopped activities in conjunction with services

I currently have a foreground service fetching GPS co-ordinates and sending them to an activity which calculates distance, time and speed. I want to constantly be getting this data and sending it until the user presses a stop button.
However, whilst I am using a foreground service to get the information, I'm worried my activity won't receive it, if it's been minimised and executed onPause or onStop methods.
Therefore is there a way to stop the activity from pausing or stopping. Or perhaps a better alternative would be, how to store the data in the service and send it/update once the activity has resumed?
You may push them into a Queue or something similar (maybe SQLite) and when your Activity is not paused/stopped you can just pop entries from your Queue.
You can't stop the Activity from getting paused/stopped since this is controlled by the Android framework.
So generally in cases like yours a FIFO data structure usually solves the problem.

Is it safe to do all cleaning up in onDestroy?

More concretely: Is it safe to place the canceling of a task in onDestroy? Also, is it safe to use onDestroy for unregistering receivers and freeing up resources?
My aim is to make sure that my task is canceled/destroyed when the Activity is destroyed, but not before.
onDestroy():
is called when the activity is destroyed and resources must be
released.
is NOT called when the activity is destroyed in a hurry (when the
system is low on resources etc).
The first case is clear: I do all cleaning in onDestroy and no problems arise. The second case is a bit of a problem though. When the Activity is destroyed and onDestroy is skipped (so I don't cancel my task), could it happen that the task continues execution, then completes and tries to update the dead Activity, so the app crashes?
We come to the real question:
When an Activity is killed and onDestroy is skipped, is everything attached to that Activity automatically destroyed? (Is onDestroy skipped only in case that everything will be wiped out altogether? Tasks, registered receivers etc)
If onDestroy is skipped does this mean that the whole app is being killed?
Let's focus on onDestroy(), because the solution is not in onPause() or onStop(). Arguments:
onStop() could be skipped when the Activity is being destroyed, just like onDestroy
onPause is called too early and too often, so it is not appropriate for the use case. Examples:
Screen lock: onPause can be called when the device screen is locked. Very often this happens like a screensaver and the user unlocks immediately because he is standing there looking at the screen. Canceling tasks and stopping everything my app is doing in such a case will only degrade user experience. I don't want my app to choke and misbehave just because of an incidental "screensaver".
In an example app I have two screens that are Activities. The user can quickly switch between them. In this app users tend to switch screens often and quickly.
Navigation: One of the screens has a map which receives location updates from the system. It records a precise graphical log of the changes in location (route), so it needs to run constantly until the Activity is closed. Normally I would register and unregister any receivers in onResume and onPause. However, this would make the app very unusable, as the updates on the map will stop every time the user navigates away. Therefore, I would like to unregister the receivers in onDestroy.
Loading list: The second screen has a list that shows data from a webservice. It takes 4 seconds to download the data. I use an AsyncTask and I know I should cancel when necessary. It should not be canceled in onPause, because it should continue loading while the user switches between screens. Therefore, I would like to cancel it in onDestroy.
There can be many more examples. Some of them might not be totally appropriate in everyone's opinion (you might even suggest using a service instead of AsyncTask). But the idea is important, and all of them have the same idea: keep on doing work that's specific to the Activity, while the Activity is paused, but ENSURE to stop doing it when the Activity is destroyed. (It does not matter whether I am using an AsyncTask or a Service. In either case, the work should be stopped when the Activity is destroyed.)
P.S. If the answer is that it is not safe to do the clean up in onDestroy, this would mean that the Android framework requires us to stop everything we are doing in onPause. And then I would not see any reason for using onDestroy...
I would like to refer you to this baby: http://developer.android.com/reference/android/content/ComponentCallbacks2.html#onTrimMemory(int)
Essentially it gives you all the places where the system finds it useful to cancel tasks and clean its memory:
Please take a closer looks at the following 2 cases:
TRIM_MEMORY_UI_HIDDEN - the process had been showing a user interface, and is no longer doing so.
TRIM_MEMORY_COMPLETE - the process is nearing the end of the background LRU list.
Which are the cases for most of what you asked.
In the same method you can also catch TRIM_MEMORY_RUNNING_CRITICAL which will alert you to a case where the system has no memory and special actions must be taken immediately.
This method has made my development life much better in similar cases.
If you just need to do some cleanup, no matter how the activity is closed, you should be able to use a combination of onSaveInstanceState() and onDestroy(). One of those should be called no matter what. Maybe have a boolean cleanupDone in your activity, which is set whenever one of the two finishes.
Concerning saving of user data, have a look at Saving Persistent State:
Google suggest a
"edit in place" user model
That is: save as soon as the user creates new data, at the latest in onPause(). This does not mean that you need to recreate the data in onResume(), just that it should have been saved.
By the way: onStop() can be skipped only on pre-Honeycomb devices, that is, as of June 2015, less than 6 % of all devices. Still, onSaveInstanceState() should be called if either onDestroy() or onStop() are omitted.
As far as I gone with android,
1 When your apps crashes every resource relevant to it are destroyed.
2 When the device changes configuration resulting the Activity to be destroyed and recreated.
3 When apps running in background and Android kill it due to running on Low Memory
apart from these the other callback method are called i e
1 when another Activity come in front , or your device locks ..etc
In all case according to your requirement you can release all your resources in onDestroy and cancel the Thread and Asyntask and stop all the services etc .if you want your task remain paused and alive while on destroy called then you can save the configuration and retain it while onCreate is called again by check is null or not.

Categories

Resources