when is onRestoreInstanceState called? - android

Sorry for my incomprehension, but I am new in the android development.
I have an application with activity A and activity B in it, and I go from activity A to activity B. When I left activity A, the onSaveInstanceState method was called, but when I went back to activity A (from activity B in the same application), the bundle in the onCreate method was null.
What can I do, to save the activity A's previous state? I only want to store the data for the application lifetime.
Can someone help me with this?
Here is my code for Activity A:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if (savedInstanceState != null)
{
Log.v("Main", savedInstanceState.getString("test"));
}
else
{
Log.v("Main", "old instance");
}
}
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
Log.v("Main", "save instance");
savedInstanceState.putString("test", "my test string");
super.onSaveInstanceState(savedInstanceState);
}
public void buttonClick(View view)
{
Intent intent = new Intent(this, Activity2.class);
startActivity(intent);
}
Here is my code for Activity B, when I press a button to go back to activity A:
public void onBack(View view)
{
NavUtils.navigateUpFromSameTask(this);
}

To answer your question, have a look at the android doc: https://developer.android.com/reference/android/app/Activity.html#onRestoreInstanceState(android.os.Bundle)
It says that onRestoreInstanceState is called after onStart() method in the activity lifecycle.

Saving and restoring state is meant to save the current temporary data that is obsolete when user exits the application.
When you minimize or leave the Activity by opening next one it might be killed by the system due to lack of resources and restarted with savedInstanceState when you get back to it. So use onSaveInstanceState() only for saving minimize-restore session data or data that should be preserved on rotation.
So if you start a new Activity in front and get back to the previous one (what you are trying to do), the Activity A might not be killed (just stopped) and restarted without going being destroyed. You can force killing it and restoring by checking Don't keep activities in developer options menu.
If you call finish() or remove the Activity from recent task list the savedInstanceState will not be passed to onCreate() since the task was cleared.
If the value must be persistent consider using SharedPreferences.

This happens because you are navigating the hard way. If you used the phone's default back button navigation, your onCreate would get the bundle passed in.
To circumvent this issue, I suggest you save your state to shared preferences as well as a back up. When the bundle is null, restore it from the shared preferences.

reference
onSaveInstanceState
... onPause()-> onSaveInstanceState() -> onStop() -> onDestory()
onRestoreInstanceState
onCreate()-> onStart()-> onRestoreInstanceState()-> onPostCreate(Bundle) ...
Or You can use LiveData. Save the states in it and observe.If the device rotates it'll update the views accordingly.

After onStart() which is after onCreate()

I used in this case a flag and SharedPreferences. This should work, and when you change the screen orientation.

Related

How to appropriately restore an android app from and back to a fragment after a system destroy

Simply speaking:
MyApp (main activity) -> MyApp (2nd Activity with fragment attached)
-> home -> AnotherApp -> MyApp.
Before AnotherApp switched back to MyApp, I took quite a while and system destroy happened. MyApp started from the main activity again, this is not good experience. And I know how to restore app using savedInstanceState, but this seems only applicable for all action in same activity.
So my question is: For an app, the last seen is a fragment in an activity, how to save or mark anything, so that when app restored from system destroy, onCreate() of main activity can pick up the variable then go back to the last seen activity with that fragment.
If I understood well, try in the MainActivity code:
#override
public void onCreate(#Nullable savedInstance){
if(savedInstance != null){
Intent intent = new Intent(getContext(), ActivityB.class);
startActivity(intent);
}
}
And in AcitivityB, save what you want overriding the onSaveInstanceState(Bundle outstate)Method and restore them by overriding the onViewStateRestored Method. Give it a shot and lemme know.

Activity backstack handling

Suppose I have activities A, B, C, D, E.
when I open application with activity A and switch to activity B and further to activity C. Suppose, somehow B gets destroyed by system. and when I press back button, I came out of app. What I really wanted was to be able to go to B if it exists otherwise A (landing page). In normal cases it's working smoothly but it's some cases where I have to interact with other apps/interfaces for eg. open url in browser. After sometime if I go back to app, I see latest page as it is but when I press back button app exits.
I have searched for solutions but couldn't find one so posting it as a question.
I know the idea of passing extra in intent and starting new intent on back press but these would not work in some cases or requires creating a backstack handler of own.
There is no guarantee that your activities will stay in memory and this is an intentional behaviour.
Your option is use to onRestoreInstanceState and onSaveInstanceState so that user do not lose critical data.
#Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// Get data
super.onRestoreInstanceState(savedInstanceState);
}
#Override
protected void onSaveInstanceState(Bundle outState) {
// Save data
super.onSaveInstanceState(outState);
}
One way which I have used in the past to validate activity state is to add e.g. a boolean attribute in your activity, set this true when activity starts, if your activity is destroyed after some time this will be false. Check state by overriding the activities onBackPressed method?
e.g.
onBackPressed(){
if status{
/*activity live*/
}
else{
/*activity destroyed/*
}
}
This might work If I understand you issue correctly.

onRestoreInstanceState is not being called on Back button pressed

I'm trying to save and restore application state as savedInstanceState.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
savedInstanceState.putInt(STATE_Tracker, 1);
super.onSaveInstanceState(savedInstanceState);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
int value = savedInstanceState.getInt(STATE_Tracker);
if (value==1){
}
else {
}
}
That code works when home button pressed. But if I press back button, and run the app again, its not working.
Any help?
From developers guide:
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. However, if the system destroys the activity due to system constraints (rather than normal app behavior), then although the actual Activity instance is gone, the system remembers that it existed such that if the user navigates back to it, the system creates a new instance of the activity using a set of saved data that describes the state of the activity when it was destroyed. The saved data that the system uses to restore the previous state is called the "instance state" and is a collection of key-value pairs stored in a Bundle object.
In other words, when you press the back button, you will not have restore behavior the lifecycle of the activity is considered completed and no longer needed, thus you don't need to restore the instance state.
If you do need however you could override
#Override
public void onBackPressed() {
super.onBackPressed();
}
And persist the state in any storage option like SharedPreference.

using onResume and onPause

Suppose I have two activities, activity1 and activity2.
I want to navigate from activity1 to activity2, get some info from activity2 and insert back it to activity1 and also I don't want to lose activity1 previous state as I left.
how can I save its state ?
what you are describing is the perfect classic reason to use the Activity.startActivityForResult() method.
this what google wrote in this method documentation:
Launch an activity for which you would like a result when it finished. When this activity exits, your onActivityResult() method will be called with the given requestCode
so what you should do is: from your activity1 start activity for result, and from activity2 use the setResult(int resultCode, Intent data) method with the data you want your activity1 to get back, and call finish() (it will get back to onActivityResult() in the same state activity1 was before..).
Override onSaveInstanceState(Bundle) in activity1 to save whatever data you want then override onRestoreInstanceState(Bundle) in the same activity to get the values back. Using Bundle, you can store pretty much any data that you want. I'd recommend something like this:
public class MainActivity extends Activity {
...
public static final String DATA1_KEY = "data1";
private boolean value1;
...
#Override
protected void onSaveInstanceState (Bundle outState) {
outState.putBoolean(DATA1_KEY, value1);
}
#Override
protected void onRestoreInstanceState (Bundle savedInstanceState) {
value1 = savedInstanceState.getBoolean(DATA1_KEY);
}
}
You should override onSaveInstanceState(Bundle savedInstanceState)
Please check this answer for example code
Or use SharedPreferences. Check this code
If you want to keep your data alive only at runtime, the consider using static members. Then you can access and manipulate these members from any activites. for example:
public class FirstActivity extends Activity
{
public static String data = null;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
data = "This is a test!";
}
}
From your second activity you can access these static variables like
public class SecondActivity extends Activity
{
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(...);
if(FirstActivity.data!=null)
{
//You can use it:
System.out.println(FirstActivity.data);
}
}
}
Of course you can add getter/setter functions to make it safer and more elegant.
If you want to store them for a longer time, the please consider using:
SharedPreferences
SQLite
or store your data in an online database.
The user performs an action in your app that starts a new activity. The current activity is stopped when the second activity is created. If the user then presses the Back button, the first activity is restarted.
When your activity is stopped, the Activity object is kept resident in memory and is recalled when the activity resumes. You don’t need to re-initialize components that were created during any of the callback methods leading up to the Resumed state. The system also keeps track of the current state for each View in the layout, so if the user entered text into an EditText widget, that content is retained so you don't need to save and restore it.
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.
CommonsWare here says:
When user "press the BACK button", then the Bundle from
onSaveInstanceState() (if any) is discarded, as the user has indicated
they are finished with the activity. The onSaveInstanceState() Bundle
is used in cases where the user has not said they are finished with
the activity (e.g., they accepted an incoming phone call) yet Android
elects to destroy the activity to free up RAM.
And documentation says:
Note that it is important to save persistent data in onPause() instead
of onSaveInstanceState(Bundle) because the later is not part of the
lifecycle callbacks, so will not be called in every situation as
described in its documentation.
In other words, put your save/restore code for non View objects in onPause() and onResume() instead of onSaveInstanceState(Bundle) and onRestoreInstanceState(Bundle).Finally I guess that you don't need to save any state if you only have View objects and if you have any other states you can use preferences,file or sqlite to save them in onPause() and retreive them in onResume().
You can see more details in these pages:
Stopping and Restarting an Activity
Saving Activity state in Android
Android wont save the current state of an activity

onSaveInstanceState is not saving my values ( onCreate input Bundle is always null )

Saving bundle (activity A):
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("test", "value");
super.onSaveInstanceState(outState);
}
Navigating to activity B;
startActivity(new Intent(getBaseContext(), B.class));
Going back to activity A:
startActivity(new Intent(getBaseContext(), A.class));
Trying to load the value I wrote to bundle in activity A:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d("MY", "saved instance is null"+ Boolean.toString(savedInstanceState == null));
}
Returns always savedInstanceState = null. What I'm missing here?
onRestoreInstanceState is never triggered when I return to main activity
I got this solve by having:
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
when re-launching the old intent that has the saved state from background. Without this flag, I think that when startActivity is called, it creates a new instance of the Activity instead of getting the old one from the stack.
There is nothing wrong with your code. Try rotating the device when on activity A. You will see the following in the Log, which means your onSaveInstanceState() is working fine:
saved instance is nullfalse
Here are an excerpt from the Android Developer Site, which you may find interesting:
The callback method in which you can save information about the current state of your activity is onSaveInstanceState(). The system calls this method before making the activity vulnerable to being destroyed and passes it a Bundle object. The Bundle is where you can store state information about the activity as name-value pairs, using methods such as putString(). Then, if the system kills your activity's process and the user navigates back to your activity, the system passes the Bundle to onCreate() so you can restore the activity state you saved during onSaveInstanceState(). If there is no state information to restore, then the Bundle passed to onCreate() is null.
Note: There's no guarantee that onSaveInstanceState() will be called before your activity is destroyed, because there are cases in which it won't be necessary to save the state (such as when the user leaves your activity using the BACK key, because the user is explicitly closing the activity). If the method is called, it is always called before onStop() and possibly before onPause().
You have to do super.onSaveInstanceState(outState) before adding content to it.
If navigating to another Activity and coming back, best way is to save it to SharedPreference in the onPause() method, which is bound to execute when a new activity is loaded. On the other Activity, the value can be accessed in onCreate() by accessing the shared preference.
In case you want to retain the state of your fragment over a rotation of the device and you wonder that onSaveInstanceState is never called:
Check whether you call super.onSaveInstanceState(outState); in all your onSaveInstanceState functions.
Check that you don't have android:configChanges in your AndroidManifest.xml.
Unless your app is running on Lollipop (API21) version of Android or newer, your
public void onSaveInstanceState (Bundle outState, PersistableBundle outPersistentState);
will NOT be called as it simply does not exist on earlier versions of the platform than 21. To support pre API 21 devices you must, instead of the above, override the following method:
public void onSaveInstanceState (Bundle outState);
This will work on API 21+ as well, so you do not need to override both methods, of course (unless you know you need to deal with PersistableBundle the new one offers).
(Copied because it worked for me)
Source: onSaveInstanceState is not getting called after screen rotation

Categories

Resources