onSaveInstanceState - WHEN can I be sure that it is called? - android

I have an activity and I have a fragment stack in it and sometimes, this stack get's lost... Although I save and restore it...
I know following:
onSaveInstanceState is not called:
a) if the user navigates back, which makes sense...
b) if the activity is finished
onSaveInstanceState is called:
a) on screen rotation
I discovered through debugging, that I can't be sure, if onSaveInstanceState is called, if screen turns black...
My app is an app, that you use for logging, meaning, you put your phone aside and come back every now and then and fill out your log... So sometimes, my activity is recreated with an empty bundle and onSaveInstanceState was not called, although my app was in the foreground and only the screen turned off...
Questions
1) what can I do to solve that problem? Do I really have to save my fragment states and the stack persistantly?
2) on screen rotation, I can be SURE that onSaveInstanceState is called, can I? Are there any other circumstances, where I can rely on onSaveInstanceState?

1) Im reffering to this thread: android life cycle you should use onPause() because you can't be sure if the app is just paused or beeing killed.
2) from developer.android.com ( Activity)
Be aware that these semantics will change slightly between
applications targeting platforms starting with HONEYCOMB vs. those
targeting prior platforms. Starting with Honeycomb, an application is
not in the killable state until its onStop() has returned. This
impacts when onSaveInstanceState(Bundle) may be called (it may be
safely called after onPause() and allows and application to safely
wait until onStop() to save persistent state.

Related

"Don't Keep Activities" is set, onSaveInstanceState not called

I'm testing that my app is able to recover from unexpected situations that lead the OS to kill my app's process due to different circumstances like low memory. To do this, I've enabled "Don't Keep Activities" in Developer Options.
I'm attempting to restore the app's state by saving state values in the Activity's Bundle through the lifecycle method onSaveInstanceState, but after setting breakpoints I've noticed that onSaveInstanceState does not get called.
Question:
Am I wrong in expecting onSaveInstanceState to be called in this scenario or might there be other factors that are preventing the method to fire? If neither, what else can I do to recover the state in this scenario?
I think two possibilities are supposed.
Your scenario is wrong
The official reference says:
Do not confuse this method with activity lifecycle callbacks such as
onPause(), which is always called when the user no longer actively
interacts with an activity, or onStop() which is called when activity
becomes invisible. One example of when onPause() and onStop() is
called and not this method is when a user navigates back from activity
B to activity A: there is no need to call onSaveInstanceState(Bundle)
on B because that particular instance will never be restored, so the
system avoids calling it. An example when onPause() is called and not
onSaveInstanceState(Bundle) is when activity B is launched in front of
activity A: the system may avoid calling onSaveInstanceState(Bundle)
on activity A if it isn't killed during the lifetime of B since the
state of the user interface of A will stay intact.
If your scenario is a 'no need to call' case, onSaveInstanceState won't be called.
Your breakpoints are wrong
If called, this method will occur after onStop() for applications
targeting platforms starting with Build.VERSION_CODES.P. For
applications targeting earlier platform versions this method will
occur before onStop() and there are no guarantees about whether it
will occur before or after onPause().
So the timing of onSaveInstanceState called depends on your targeting platform.
An easy workaround is to backup data with SharedPreference, etc. in onPause.

Confused about this Android Activity life cycle scenario - OnCreate gets called whenever app goes back to foreground

To make things as simple and easy to follow I created a new empty project in Android Studio with only one MainActivity and Hello World text. This could not by any means be a consuming app. I also did override all the important life-cycle methods like onCreate ,onStart, onResume, onPause, onSaveInstanceState, onStop, onDestroy and logged them to see what is happening.
So here is what I am experiencing (in each step the list of life-cycle callbacks is printed)
After app/activity launches (expected behavior)
onCreate onStart onResume
After I press home button / app goes in background (expected behavior)
onPause onSaveInstanceState onStop
After I immediately return / app goes in foreground (expected behavior)
onStart onResume
After I press home button (app goes in background) and I open another app like Facebook and immediately return back to my app I expect it to resume, but instead onCreate gets called.
onCreate onStart onRestoreInstanceState onResume
I find this really strange because I am not low on memory on my device and I have basically empty activity. Is there some flag I can set in the manifest or any solution that will not recreate my activity when I return to it ?
Please don't suggest I save and restore state using onSaveInstanceState and onRestoreInstanceState, I am specifically interested why onCreate is called when I move my app back in foreground. I've done many apps in the past and I don't remember having this issue before with activities being destroyed so early.
I open another app like Facebook and immediately return back to my app I expect it to resume, but instead onCreate gets called
Apparently, Android terminated your process, either of its own volition to free up system RAM or at the behest of some other app (e.g., task manager). This may also be device-specific, as device manufacturers can tweak how this stuff works, from what I can tell.
I find this really strange because I am not low on memory on my device
Perhaps Android or the task manager disagreed with you. Perhaps your means of determining free memory isn't the same as what the out-of-memory killer uses. Also, bear in mind that Facebook uses some techniques that cause them to use an outsize amount of RAM for their process, so they will cause more of this sort of thing than will a leaner app.
Is there some flag I can set in the manifest or any solution that will not recreate my activity when I return to it ?
No.
That being said, there are a variety of factors that the out-of-memory killer will use to determine what process(es) to terminate to free up memory, including:
process importance (are you in the foreground? do you have a service running?)
process age
process working set size (i.e., memory usage)
Please don't suggest I save and restore state using onSaveInstanceState and onRestoreInstanceState
I would suggest to all Android developers that they save and restore instance state using onSaveInstanceState() and onRestoreInstanceState(). That helps with configuration changes as well as these sorts of process termination scenarios.
I've done many apps in the past and I don't remember having this issue before with activities being destroyed so early.
Perhaps you did not test them on this device, or on this device and OS version (if you got an upgrade). Perhaps you did not test them in this scenario (e.g., launching Facebook). Perhaps you did not test them with the other apps you have running that might be affecting matters. Since you wrote those other apps, presumably you can re-run your tests using those apps, for more of an apples-to-apples comparison.
You can (and should) make this happen for testing by turning on the "don't keep activities" developer option. You cannot prevent it from happening. This can always happen, and you must handle it gracefully.
Please don't suggest I save and restore state using onSaveInstanceState and onRestoreInstanceState
That's what you have to do if you want your app to work reliably.
The android lifecycle guarantees some things and provides no guarantees about others. It's guaranteed that if your activity was destroyed, onCreate() will be called before onStart() and onStart() before onResume().
However, in most cases there is no guarantee that your activity will NOT be destroyed once it goes into the background. The reasons are not fully spelled out because this gives google (and individual android distributions) the freedom to modify such things in the future. Part of the downside of having no such guarantee means that just because your activity did not get destroyed in the past, does not mean that in a different version of android, different device, or different circumstance, that it will not get destroyed in the present.
If you must know the exact reason why, I would suggest monitoring the log output very closely, it may contain some clue. But keep in mind that android does not intend for the developer to try to avoid this, only to resume from where you left off when the activity is re-created.

How can we guarantee that onPause will be called?

Going of this question
android save game state in onPause or onDestroy?
The answer highlighted that the person asking the question should save game state in onPause because the onDestroy documentation says "There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away." In these situations, how can we ensure onPause will be called? Is it possible to control what methods are called in these situations? Seems unpredictable
onPause will be called every time your activity leaves the screen, before it is finished or if something overlays your activity that keeps the user from interacting with your activity.
You don't need to worry that onPause is not called.
For more information look into the starting and stopping activity training or the Lifecycle Api Docs
You should save temporary instance state in onSaveInstanceState(). This method recieves a Bundle parameter which you can use to write state to. The Bundle is then sent to onCreate() when your app is restarted.
If you need to save instance state more permanently, then save it to a database or SharedPreferences. According to http://developer.android.com/training/basics/activity-lifecycle/stopping.html, you should use onStop() for more CPU-intensive operations rather than onPause(). I don't think you need to worry about onPause() being called in normal use cases. As far as I can tell, it is guaranteed. (Of course, there are always catastrophic failures, such as the user pulling out the battery of the device, but there's not much you can do about that.)
It's almost certain that onPause() will always be called. The reasoning is that it's highly unlikely the "system" will aggressively kill an active (i.e., visible) Activity.
In order to free resources, the Android OS effectively reserves the right to kill dormant processes - in particular ones that have been long-running but not recently used. In order for your Activity (and its process) to qualify for this, at some point you must have sent the Activity to a background state, e.g., pressed HOME or started another app's Activity. The simple fact your Activity is no longer visible means it will have been paused and onPause() will have been called. It's almost certain that the Activity will have been stopped and onStop() will have also been called.
What you have to remember is Android has been around for a while now and early devices had RAM measured in 100s of MB and the system behaviour possibilities and documentation reflects this. More recent devices have RAM measured in GB (even 10s of GB) so unless a user really pushes their device to the limitations of its resources, aggressive clean-up of app processes becomes less likely.
You can show Dialog for User to Act Accordingly.When Dialog will be opened to ask user that he wants to quit or not,Activity will definitely call onPause() and at this time you can write your game state saving code. Its better to write code on onPause() because at onDestroy() resources are freed by os.

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.

Keep activity in paused state - Android

I have an application with 3 tabs with one activity per tab. When I am switching between first two activities, the activity, which is going to background passes the onPause() state, while the new one becomes active and onResume() is called. That’s good, because both activities have a complex UI and rendering them takes 2-3 seconds, but when they are kept in paused state, they are resumed quickly.
But when I click on the 3rd tab, then the application behavior is different, the activity, which is going to background, is completely destroyed (it passes onPause(), onStop() and onDestroy()).
Any idea why there is difference in behavior? Is there a way to force the activity to remain in a paused state when user switches to another activity within the application?
Thanks
STeN
This behaviour can even be different on another device or in any other context (different amount of available memory, etc).
You have the guarantee that
onResume() is called when an Activity is going foreground
onPause() is called when the Activity is going background,
and this is the only guarantee you have. (More details on the Activity lifecycle here).
So you can make absolutely no assumption about the calling of onStop() and onDestroy(). They may be called or not each time you are switching from a tab to another, and your application needs being able to handle this.
The reason why the first activity is destroyed may be caused by the lack of heap memory. If Android is running out of memory it kills background activities. This behaviour cannot be influenced by the developer since the whole system would slow down and crash if there's not enough memory left to keeps things going.

Categories

Resources