when we resume app after some time ContainerHolderSinglton.getContainerHolder().getContainer() becomes null
I assume this happens when your app is in the background for some time, and you come back to the application.
This happens because your App's process gets killed as Android system need resources.
You should save all the variables you want restored in the onSaveInstanceState() method of your Activity / Fragments. You should save the variables inside the singletons and restore them in onCreate(Bundle savedInstanceState) method, from the savedInstanceState.
Android Activity Lifecycle
Related
Having a bug which relate to the os kill/restore the activity (or the app?).
After some debug find if set don't keep activities and set Background process limit to no background process will cause different behavior.
saw this post, but it does not answer the question here.
Here is what observed:
In the application it will start dagger component and it maintains some app scope singleton object, and in activity A (the default launch activity) it will by user's action to launch activity B, in B it creates and hosts a fragment. There will be some data stored in the app scope singleton object to work with the fragment.
In case of only have the don't keep activities set, when minimize the app the activities onDestroy() is called, and when re-open the app it restores the last active activity (say the user opened the activity B, the B will be re-created with the fragment restored with the savedInstanceState). In this case the app scope singleton objects managed by the dagger are still alive, so the state is completely restored to what it was before minimized the app.
But if have both don't keep activities and set Background process limit to no background process, then when minimize the app, the activity's onDestroy() is not call (only call up to the onStop()).
The behavior change is at this time if re-open the app, it will start from application onCreate(), and recreate the dagger's component. So the state before minimize the app is not re-stored.
But the os seems still remembers the last activity is B and the B's
onCreate(savedInstanceState: Bundle?)
is called with savedInstanceState having the data saved when minimizing the app, so does B's fragment.
And it is a messed up, it has data from the savedInstanceState, but the app scope singleton objects are fresh ones that do not have the data to work with the ones from the savedInstanceState.
Anyone knows in this case where is the savedInstance saved, and why although the application seems to be recreated but still the last activity (not the launching activity) is re-stored?
The savedInstanceState bundle is explicitly intended to do as you describe. Regardless of whether a background activity is destroyed to conserve memory (e.g. "don't keep activities" is turned on) or whether an entire app process is killed to conserve memory (e.g. "background process limit" is zero), the framework will provide your app the ability to save state information into the savedInstanceState bundle and will subsequently return that state information to you in future calls to onCreate().
The only situation in which savedInstanceState will be null is the very first time your activity starts up. It doesn't matter whether your app's process is killed or not; if your activity is restored you will receive a non-null savedInstanceState bundle.
I have three activities in my application.
From the first one i started the second, and from the second i started the third. When the process of my app is killed by the system and i launch it again i see only the last active activity is being created. And it seems the only one that gets Bundle object as a parameter to its onCreate method.
There are two things I am curious of:
If the activity at the top of the stack is the only one that gets its bundle, why each of my activities got their callback (onSaveInstanceState) called just before their onStop() method.
If only one of my activities can retain original state, what about the others? Did they lose all their state just because system decided to kill my app process? Should i restore them manually? What about views on them? (normally views get their state back without needing me to put something into the bundle and later restore if i am not mistaken)
The default behavior is this (tested on 4.1.1):
When you start a new activity, onSaveInstanceState of the previous activity is being called
When the system kills the app, the state of activities back-stack is being saved
When you restart the app, the last seen activity is being shown and its onRestoreInstanceState is being called
When you navigate back and pop activities from the back stack, state of each of them will be restored with a call to onRestoreInstanceState passing the bundle that was obtained from the first step above.
Therefore, the answers to your questions are:
All activities will be restored, but not at once - the last one seen is restored immediately, while the others will be restored when you navigate back.
All simple views (e.g. EditText) will automatically restore their state. In order for this to happen, you need to make sure that a) you did not override onSaveInstanceState or onRestoreInstanceState without call to super implementations b) the views that should be restored have unique IDs in view hierarchy
onStop is called on previous activity when you create a new activity, so you are saving the state! Your previous activity's onCreate will be called, if it's destroyed, so don't worry about recreating views. Are you sure app is killed? An app is not killed when it loses view. Android will keep it in memory as long as it doesn't need to free memory.
I know this is not a question but I've been struggling with this issue for a long time, whenever i work with fragments, when I leave the app (not destroyed, just click on home button) and I return to it after some amount of time, it gives nullpointerexception for all my variables and everything, I know this is a memory issue where it clears some space for other apps, but how can I workaround this and protect my objects from beeing destroyed,
thank you all
Have a look at
onSaveInstanceState(..)
This gets called when user minimizes your app -> by hitting the home button or when the OS is about to destroy your app. At this point you can save all the needed variables in the bundle that is passed in. This bundle is written to disk and passed back when your activity is recreated:
If you just want to retrieve your variables in the Activity you can use:
protected void onRestoreInstanceState (Bundle savedInstanceState)
Fragment do not have onRestoreInstanceState(...) but you can use onActivityCreated(...) to access the bundle if you want to retrieve your variables in the fragment.
Note: Even if the system destroys your activity while it's stopped, it still retains the state
of the View objects (such as text in an EditText) in a Bundle (a blob
of key-value pairs) and restores them if the user navigates back to
the same instance of the activity (the next lesson talks more about
using a Bundle to save other state data in case your activity is
destroyed and recreated).
the same instance of the activity
how it could be exact instance when it is destroyed and recreated , isn't it going to be a new memory block (another instance ), could anyone help me to clear this point ?
Unfortunately the documentation isn't very clear in a lot of areas. This is one of them.
In theory, if Android were to destroy your activity while it is stopped, then it would call onDestroy() and the GC would reclaim the memory. In actual fact, Android never destroys individual activities to free up memory. What it actually does is it kills the entire OS process instead. In this case, onDestroy() never gets called on any of the activities in the process. The GC doesn't bother to clean up anything, because the VM (Virtual Machine) just dies immediately along with everything else in the process and the entire amount of memory in use by the process is reclaimed by the operating system.
When your user navigates back to your application, Android creates a completely new process for your application and then it will create a new instance of your activity. In this case it will, of course, get a completely new block of memory for the instance. You will also see the constructor get called and onCreate() will also be called. However, since Android saves the state of the activity's views, that state will be restored by the activity by the call to super.onCreate().
There are a few cases where Android will destroy an instance of an activity and create a new one automatically. This is done, for example, during a configuration (ie: orientation) change. In that case, Android calls onDestroy() on the old instance and creates a new instance of the activity. The new instance gets the saved state of the old instance and can therefore restore the state of the views as able. In this case, since a new instance is being created, it will, of course, have a different address in memory.
Once a component is destroyed, it is effectively dead and the memory it is using can be reclaimed by the GC. Android will never reanimate a dead instance.
Hopefully this clarifies the situation for you.
EDIT Add more details
Android keeps track of tasks and the activities in those tasks in its own internal data structures. For each activity, it keeps a copy of the Intent that started the activity, the most recent Intent sent to that activity and it keeps a Bundle containing the saved state of that activity. Android calls onSaveInstanceState() on an activity to give the activity a chance to save anything that it will need to restore the activity if Android decides to kill it. The default implementation of onSaveInstanceState() saves the state of all the activity's views. Your implementation needs to save anything else that the activity will need to restore itself if it is killed and recreated by Android (for whatever reason). Your activity's private member variables and static variables are not automatically saved and restored in the Bundle, so if you need these to be able to recreate your activity properly you must save them yourself using the Bundle provided by onSaveInstanceState(). Static variables will stay around for the lifetime of the application's process, but since Android can kill the process (to reclaim resources) at any time, without warning, you also cannot rely on static variables always having the expected values (in the case where Android has killed and recreated your process).
If your activity (or process) is killed by Android and the user later navigates back to your activity, Android uses the information it has in its internal data structures to create a new instance of the activity. It then calls onCreate() on the new instance passing the saved instance state Bundle as a parameter. This can then be used to restore the activity to the state it had before the original instance was killed. Android will also call onRestoreInstanceState() after calling onStart() so that you can also do your restoration of state in that method if you don't want to do it in onCreate().
Note: Remember that anything you want to save/restore in a Bundle must be either a primitive (int, boolean, etc.) or it must implement Serializable or Parcelable.
The documentation of onSaveInstanceState() contains some useful information about this as well.
The state is stored, but the activity is destroyed to save memory. So, when the user is in an Activity A and goes to the Activity B, the Activity A is destroyed, but the state is stored. When the user presses the back button, the state will be loaded and everything will be restored.
The system does it when the activity call onStop and onStart. I didn't make any test, I'm just saying what I understood.
Does anyone know of an exhaustive list of when the savedInstanceState bundle will be used in an activity?
I know it's used when the device orientation changes. However, it doesn't seem to be used when the user force closes the app from the Android settings, but this might be due to something in my code.
What other cases are there?
To be clear, by "used" I mean when onCreate() is called, the savedInstanceState bundle is not null and contains the data I passed into it the last time onSaveInstanceState() was called.
It's used when the Activity is forcefully terminated by the OS (ex: when your Activity is in the background and another task needs resources). When this happens, onSaveInstanceState(Bundle outstate) will be called and it's up to your app to add any state data you want to save in outstate.
When the user resumes your Activity, onCreate(Bundle savedInstanceState) gets called and savedInstanceState will be non-null if your Activity was terminated in a scenario described above. Your app can then grab the data from savedInstanceState and regenerate your Activity's state to how it was when the user last saw it.
Basically in onCreate, when savedInstanceState is null, then it means this is a 'fresh' launch of your Activity. And when it's non-null (if your app saved the data in onSaveInstanceState(...), it means the Activity state needs to be recreated.
onSaveInstanceState is used to store data only for application lifetime (i.e. temporarily)
The data is held in memory only until the application is alive, in other words this data is lost when the application closes, so in your case when you force close the app onSaveInstanceState is not used.
It can only be called when you do operations while your application is still alive, for e.g. when you change the screen orientation the activity is still intact so onSaveInstanceState is called.
However if you want to permanently store the data you would have to use SharedPreferences and SQLite database.