Hello I am just a little confused after reading these materials on Tasks and Back Stack, Android Developer Guide:
It says:
When Activity A starts Activity B, Activity A is stopped, but the system retains its state (such as scroll position and text entered into forms). If the user presses the Back button while in Activity B, Activity A resumes with its state restored.
While in the APIs reference for onSaveInstanceState() method, it says:
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.
The above two situations seem identical to me ("press the Back button to Activity A" and "navigate back from Activity B to Activity A"). But I don't understand why while the former says Activity A resumes with its previous state restored while the latter says the particular instance of Activity B will never be restored. Any explanations?
Thanks in advance!
I think the first one is saying that A will be saved so it can be restored, and the second one is saying that B will not be saved because it can't be restored.
Related
I have researched numerous posts regarding Activity back stacks, as well as the Android Developer website, but still can't find a solution to a problem I'm having.
Scenario:
I have Activity A, I navigate to Actvity B, from A and then press the back button to go to Activity A again:
Actvity A --> Activity B --> Actvity A
Nothing out of the ordinary..
Problem
When I press the back button to go to from Activity B --> Activity A, Activity B is not destroyed straight away, as expected it goes into a pause state and this is where I have strange problem. If I want to return to Activity B from Activity A and IF Activity B is still in a pause state all its life cycle methods are called when use startActivity(B) from Activity A:
Activity B - onCreate() > onPause > onStop > onDestroy <-- why is this happening
At this point, to me it shouldn't exist anymore, and I can't explain why it went through all its lifecycle methods, rather than just the start initialisation lifecycle methods. The fall out from this strange behaviour is that the Activity is still visible on screen but doesn't populate a RecyclerView which in first initialisation did so as expected. At this point if I press back Activity B enters a pause state again.
If Activity B is in a pause state (Activity A is at top of stack) and the framework ends Activity B through lifecycle callbacks and I navigate to Activity B again from A it works as expected (RecyclerView is populated), basically a fresh instance always works fine.
All I can assume, when referring to the Activity Lifecycle diagram, is that Activity B enters a pause state, however is destroyed without calling onStop, onDestroy etc.. meaning any Activity clean up operations I have in those callbacks aren't happening?
Things I've Tried
Changing various Intent filters, and combinations, when starting Activity B:
FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_SINGLE_TOP
Calling finish() when onBackPressed() is called in Activity B
Various other fingers crossed and hope changes, nothing seems to work.
Can anyone help please!
Ok, so I found the answer to the problem - not obvious at first, but now I understand what was happening.
The root cause of the problem was to do with 2 instances of the same Activity (Activity B) referencing the same Objects (Objects supplied from DI library).
Firstly when returning to Activity A from Activity B, Activity B was not immediately destroyed, and this causes a complication - this instance would never be reused, however still existed for a period of a few seconds. In this situation when using startActivity(B) from Activity A it would create a new instance and destroy the old (hence why I was seeing logging in both creation and activity ending callbacks), if it still existed. In this scenario both instances were sharing the same object, and this object "cleaned up" the Activity when destroyed. So the object (Presenter in this case) was being told by the old instance that it should clean up the Activity as its being destroyed, however this was not the case, because a new instance had been created.
The solution
Quite simple really, every time a new instance of Activity B was created, store in the Presenter a unique number (startId), and when Activity B called onDestroy() pass its current unique number, and check they match - if they don't match its not the latest instance, so do nothing. Very similar idea when you want to stop a Service, and check its the latest Activity calling the service from the startId.
Personally I don't know why Activities aren't destroyed straight away on pressing back, but thats the reason why this was happening.
I have an object that implements Parcelable so that when the screen is rotated, the data is deserialized and display on screen. However, when I press the back button and click on activity "A" again, the data isn't there anymore. Why is onSaveInstanceState null after you press back button?
When your activity is destroyed because the user presses Back or the activity finishes itself, the system's concept of that Activity instance is gone forever because the behavior indicates the activity is no longer needed.
onSaveInstaceState will have value only if the activity is Recreated by the system.
Check Recreating an Activity for more info.
When a user knowingly leaves the Activity, the onSaveInstanceState is not called. It is called when the system destroys and recreates the Activity.
For this reason, you are getting null in onRestoreInstanceState.
Refer -
http://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState%28android.os.Bundle%29
I wrote an Android app with several Activities and a Main Activity. When I go from the Main Activity to lets say Activity B, I want to "pause" the Main Activity, when the back button is pressed it should go back and reactivate the Main Activity instead of calling onCreate().
This shall work with all Activities, so if I click on a button to start Activity B, it shall also reactivate the old Activity B instead of creating a new state with onCreate().
How can I realize this?
PS: I already tried it with parcelable, but this do only work, if I close the application or something unexpected happens.
It's always possible that the first activity may be destroyed when you start another activity. It will be recreated when you go back to it. Every app should be written with this possibility in mind. To make sure your activities can handle being destroyed and recreated, turn on the "don't keep activities" developer option.
It is by default in Android. If you Start Activity B from Activity A then activity A goes in stopped state. Below methods will be called of Activity A
onPause()
onStop()
When you tap on Back key on Activity B. Below methods of Activity A will be called.
onRestart()
onStart()
onResume()
For reactivating Activity B, you can set Activity B launch mode as singleInstance. This will make sure that only single instance of Activity B will be created. onCreate will be not be called again. onNewIntent will be called when that activity is reactivated.
Refer: http://developer.android.com/guide/topics/manifest/activity-element.html#lmode
Activities live in stack order. Each activity has its life cycle. When you close an activity (Activity B in your example) it eventually reaches onDestroy() method and removed from the stack order. It is by default in Android and there's nothing you can do about it.
What you can do is rewrite the onStop() method in Activity B and save some activity data (like text in EditText, for example) in SharedPreferences - read here. Then in your onCreate() method you can call for SharedPreferences, check if it's not empty and restore the text in the EditText by pulling appropriate value by key.
In answering a question here on SO about when onDestroy is called what appears to be an inconsistency in the Android docs arose.
According to the android docs regarding the task and backstack
"When the user presses the Back button, the current activity is popped
from the top of the stack (the activity is destroyed) and the previous
activity resumes (the previous state of its UI is restored). "
However at the same time, the android lifecycle suggests that activities are not automatically destroyed but rather paused if the UI is partially hidden, stopped if the UI is totally hidden, and destroyed only if the system is low on resources.
These are two opposite positions. So my questions is - which is it?
Shout out to #Raghunandan for going back and forth with me in comments for a while. Hopefully we will get an answer.
They are both correct in their context. Maybe the lifecycle should say "destroyed only if system is low on resources OR it is popped form the stack".
Consider this for example. You start with activity A, then start activity B from A, then start activity C from B.
Now both A and B are paused and stopped, but not destroyed.
If C is heavy on resources, A or B may be destroyed.
Now press Back button from Activity C, you are back to Activity B
Activity C is paused, stopped and destroyed .
Now press Back button again, you are back to Activity A
Activity B is paused, stopped, and destroyed
System tries to keep all the activity instances so they can be re-opened quickly. But when an activity is popped from the stack, there is no way for user to re-open them in future, at least not the same instance.
There is no contradiction in these two statements.
onDestroy is called when you press BACK unless you override onBackPressed not to call finish() or do a strange thing of overriding finish and not calling super.finish().
If you don't stop the call to Activity.finish, onDestroy is always called.
The other statement speaks nothing about pressing BACK and I can find nowhere under the link you have provided here that
and destroyed only if the system is low on resources.
Additinally to onDestroy being called when app is low on resources (which strangely doesn't happen on my phone; I get OOM) it is called when 20 other Activities globally (from all applications) are started after this one.
I also encouarge you to check out yet another answer on when onDestroy is called again for a real reason of onDestroy not being called.
I have an Activity A with a button on it which when clicked navigates to Activity B. Now from this Activity B when the back button is pressed i get back to Activity A which is quite obvious. But once again when i click on the button on Activity A a new instance of Activity B is launched.
My query: Is there a way so that when i press the back button on Activity B it's instance is stored and so when i again click the button on Activity A the saved instance of B is launched instead of a new one.
Hoping for a solution..
if you don't want to pass data.. or just want to go back on Previous activity
finish() in onClick
http://developer.android.com/reference/android/app/Activity.html
In addition, the method onSaveInstanceState(Bundle) is called before placing the activity in such a background state, allowing you to save away any dynamic instance state in your activity into the given Bundle, to be later received in onCreate(Bundle) if the activity needs to be re-created.
To think that it won't be easy to deal with it. The activity in the android can be store but you cannot call the android system to using that instance of your when you navigate to the activity B.
Read this link http://developer.android.com/reference/android/app/Activity.html
it give all information that you can do with it but not all as you want.
When you navigate from activity B to activity A the android itself has been store your activity B's instance temporarily in the memory and that instance will destroy completely anytime later. If you navigate it from A to B again, then the instance of Activity B will be reuse again if it still exist in the memory otherwise it recreate the activity again. In any case the activity B is reuse or recreate, the method onCreate is always call (all method in Lifecycle like onResume ...etc) then all data of your activity B is now new data that's not your old data before you navigate it to the activity A. This is what android system doing so that you cannot launch activity B without calling those method.
if you want the activity B look like the same as before navigate to activity A you should probably saving the necessary data in the method onPause() on the activity B then set those data back to the component of activity B when it call onCreate(). The method onSaveInstanceState(Bundle) should not be use in this case because the android os version which is before honeycomb (3.0) is not invoked that method.
This could be difficult to deal if you are working with online data or listview, webview ...etc and also save data by your own it could the risk to your application itself.
Anyway I hope this could be some help to you.