I need my Android app to save it's state to disk when its activity is put in the background or killed. It's been suggested that I start a thread when onPause() is called and perform any expensive I/O procedures there (see Saving/loading document state quickly and robustly for image editor).
In what situations will the OS kill the thread and how commonly do these situations occur?
I assume it will be like how Activities are dealt with where the OS can arbitrary decide to kill the thread but will mostly only do this when resources are extremely limited. It would be nice to find some specific documentation of this though.
From playing around, with some test code, a background thread started in onPause() will run indefinitely in the background on my device (I tried loading lots of apps and couldn't get it to be killed).
For my specific app, I'm writing a bitmap editor where I'm using the Command pattern and the Memento pattern to allow undo and redo of edits. I'd like the user to be able to undo/redo their edits even e.g. the user gets a phone call and the activity is killed when it is put in the background. The best solution I can think of is to use a background thread to constantly save my command and memento objects to disk during application use and to finish up saving any objects that are left in a background thread if onPause is called. In the worse case, if the thread is killed I'll only lose some edits.
In what situations will the OS kill the thread and how commonly do these situations occur?
The OS will not kill the thread, unless it is killing the process -- Android does not do anything with threads you create yourself. If you are the foreground process, you will not be killed. The odds of Android killing the process within a few seconds of you losing the foreground (after onPause()) are miniscule. The documentation on process lifetime -- what there is of it -- can be found here.
Your thread may be killed at any time after the activity is destroyed, or it may never be killed. Depending upon such a thread is very bad form -- you could end up with a half-completed operation, or with a thread that sticks around forever.
If you wish to perform a background operation that continues even when there is no foreground activity, you almost always want to run it inside a Service. On the other hand, the service is less likely to be killed, but there's no guarantee unless you use "startForeground". This will end up displaying a notification to the user that something is happening in the background, but as far as I know it's the only way of running an asynchronous background thread that is guaranteed not to be killed.
Honestly, the right answer is to make sure that there is never any temporary process state that will take a long time to save. If you are having to write a large file to reflect a few user changes, consider maintaining a "transaction log" which you can use to create a restartable save operation. Given this, you can safely run your saves in a service and know that even if it gets killed, it will be automatically restarted when resources become available.
Normally, saving your state in onPause is the right thing to do if it's quick. I don't think it's clearly documented when a process is killed, but you sometimes see it in logcat when you run some demanding apps (say, after running Google Earth and Browser).
There's also an option in the Android DevTools to automatically destroy activities as you navigate away from them, although that probably doesn't extend to the process. (DevTools are on the emulator, and on some rooted phones).
I think your approach sound reasonable - use a low-priority thread to constantly update the save data, and give it normal priority in onPause, and set a flag in onPause that tells it to terminate after it finishes.
Obviously, you'll need to make sure you don't run into synchronization issues if you get to onResume immediately after onPause (i.e. while the thread is still busy saving).
Related
It is meant for Services, Activities, Fragments and so on. Does it only occur in the case of some heavy operations in the UI thread?
Also just wondering - which method of those components can throw/rise ANR?
In Android, the system guards against applications that are insufficiently responsive for a period of time by displaying a dialog that says your app has stopped responding. At this point, your app has been unresponsive for a considerable period of time so the system offers the user an option to quit the app
Generally, the system displays an ANR if an application cannot respond to user input. For example, if an application blocks on some I/O operation (frequently a network access) on the UI thread so the system can't process incoming user input events. Or perhaps the app spends too much time building an elaborate in-memory structure or computing the next move in a game on the UI thread. It's always important to make sure these computations are efficient, but even the most efficient code still takes time to run.
In Android, application responsiveness is monitored by the Activity Manager and Window Manager system services. Android will display the ANR dialog for a particular application when it detects one of the following conditions:
No response to an input event (such as key press or screen touch events) within 5 seconds.
A BroadcastReceiver hasn't finished executing within 10 seconds.
Picked out the parts which are relevant to your question.
But for more information, check out the android doc where I got this from.
And ANR usually occurs when you are running long running operations (ex. networking) on the main thread.
I've developed a simple application that loads four mobile webviews side by side.
On a fresh install the app fully opens and loads these pages in under 0.5 seconds.
However if i minimize this app, for some reason its "cached background process" is over 200mbs! sometimes 250... Seems completely unnecessary as the app loads lightning fast on a fresh install
How can I clear this cache when the app is minimized (onbackpressed etc)
You need not to worry about cached memory as system will reclaim it when required.
however if still you want to do something about it you can call finish() in your onStop() method.
also this is a great answer on this topic by CommonsWare.
"cached background processes" usually refers to processes that do not
have a foreground activity and do not have a running service. These
processes are kept in memory simply because we have enough memory to
do so, and therefore, as you note, the user can switch back to these
processes quickly. As Android starts to need more system RAM for yet
other processes, the "cached background processes" tend to be the
processes that get terminated to free up system RAM
I am using a passcode lock on my app. I set a varibale to true/false in shared preferences using the logic in this answer. But this approach doesn't work when I kill the app while still on foreground (using recent apps). Looks like killing the app kills my TimerTask which is scheduled for 2secs and hence the variable never gets set.
I have tried using services to do the same but no luck, even services get killed when the app is killed. Any workaround for this? Please help!!
You can use Service with START_STICKY, which will be recreated after killing. Check AlarmManager for events that will be launched by system even if your app is closed.
I personally suggest using the AlarmManager, instead of keeping long-running services.
The best way to execute background tasks in an efficient way is to use an IntentService
http://developer.android.com/reference/android/app/IntentService.html
An IntentService is going to run in a separate thread as long as the task requires and will be killed afterwards.
Also it will enqueue requests and deal with the queue itself
I'm writing an android app that involves one AudioTrack and one AudioRecord. They run in two different threads, and both of them need to continue to run and not being killed when low memory/CPU even if the app is running in the background. I searched about this and I know I could probably use AsyncTask (just like in music streaming app). However, I'm no exactly sure how to do it because the thread that runs AudioTrack is first created (once a certain button on the main activity is pressed), then this thread will create another thread that runs AudioRecord (by creating a Runnable).
I searched about this and I know I could probably use AsyncTask (just like in music streaming app)
No. Your issue is not the threads, but the process.
both of them need to continue to run and not being killed when low memory/CPU even if the app is running in the background
Strictly speaking, that is not possible. The closest that you will get will be to use a Service that in turn uses startForeground() to indicate that it has foreground priority. That will minimize the probability that Android will terminate your process due to low memory conditions, but it will not eliminate it.
Also, please note that you will need the CPU to be powered on to perform your audio tasks. That, in turn, will require a WakeLock. This is going to seriously hammer the user's battery, to the point where you should advise users to keep the device on a charger. That will be particularly important in the future, where the "Doze mode" of the upcoming "M" Android release will block your use of WakeLocks if the device is idle, unmoving, and not on a charger.
Is there some way to prevent the application from closing? Can I do it in the OnDestroy?
If your question is where you can prevent your application from being closed that is not possible. The system has the right to close when it runs on low resources or when the user wants to - through a task killer or the incorporated system in ICS.
OnDestroy just notifies you about that, you can't "revive" the application there.
You cannot prevent the application from closing as the kernel may force it to shut down if the device becomes low on resources. Normally, when the system is low on resources, the kernel will inform the application that it wishes to close it. Allowing the application to execute its onDestroy method and then close.
Your onDestroymethod can be useful for saving state. Here's a skeleton example:
protected void onDestroy() {
super.onDestroy();
//state is saved here.
}
However, it's worth remembering that you're not guaranteed that onDestroy() will execute. The kernel may or may not give it time to do so. You should check out the Activity Life Cycle for further information
Not sure what your question is, gonna try interpret it and i think this is what you need:
If you want your application to continue a process that it is running regardless of the application state, create a foreground service that will run the process instead, and can be binded to the application when needed.
http://developer.android.com/reference/android/app/Service.html