如何使用保存实例状态去保存活动状态?

我一直在研究 Android SDK 平台,有点不清楚如何保存应用程序的状态。 因此,考虑到对“你好,Android”示例的这个小改动:

package com.android.hello;

import android.app.Activity;
import android.os.Bundle;
import android.widget.TextView;

public class HelloAndroid extends Activity {

private TextView mTextView = null;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

mTextView = new TextView(this);

if (savedInstanceState == null) {
mTextView.setText(“Welcome to HelloAndroid!”);
} else {
mTextView.setText(“Welcome back.”);
}

setContentView(mTextView);


}

}

我认为对于最简单的情况就足够了,但无论我如何离开应用程序,它总是以第一条消息作为响应。

我确信解决方案就像覆盖 onPause 或类似的东西一样简单,但我已经在文档中摸索了 30 分钟左右,但没有发现任何明显的东西。

You need to override onSaveInstanceState(Bundle savedInstanceState) and write the application state values you want to change to the Bundle parameter like this:

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
  super.onSaveInstanceState(savedInstanceState);
  // Save UI state changes to the savedInstanceState.
  // This bundle will be passed to onCreate if the process is
  // killed and restarted.
  savedInstanceState.putBoolean("MyBoolean", true);
  savedInstanceState.putDouble("myDouble", 1.9);
  savedInstanceState.putInt("MyInt", 1);
  savedInstanceState.putString("MyString", "Welcome back to Android");
  // etc.
}

The Bundle is essentially a way of storing a NVP ("Name-Value Pair") map, and it will get passed in to onCreate() and also onRestoreInstanceState() where you would then extract the values from activity like this:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
  super.onRestoreInstanceState(savedInstanceState);
  // Restore UI state from the savedInstanceState.
  // This bundle has also been passed to onCreate.
  boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
  double myDouble = savedInstanceState.getDouble("myDouble");
  int myInt = savedInstanceState.getInt("MyInt");
  String myString = savedInstanceState.getString("MyString");
}

Or from a fragment.

@Override
public void onViewStateRestored(@Nullable Bundle savedInstanceState) {
    super.onViewStateRestored(savedInstanceState);
    // Restore UI state from the savedInstanceState.
    // This bundle has also been passed to onCreate.
    boolean myBoolean = savedInstanceState.getBoolean("MyBoolean");
    double myDouble = savedInstanceState.getDouble("myDouble");
    int myInt = savedInstanceState.getInt("MyInt");
    String myString = savedInstanceState.getString("MyString");
}

You would usually use this technique to store instance values for your application (selections, unsaved text, etc.).

Note that it is not safe to use onSaveInstanceState and onRestoreInstanceState for persistent data, according to the documentation on Activity.

The document states (in the 'Activity Lifecycle' section):

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 persistent data in onPause() and onResume()!

For further clarification, here's the onSaveInstanceState() documentation:

This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state. For example, if activity B is launched in front of activity A, and at some point activity A is killed to reclaim resources, activity A will have a chance to save the current state of its user interface via this method so that when the user returns to activity A, the state of the user interface can be restored via onCreate(Bundle) or onRestoreInstanceState(Bundle).

onSaveInstanceState is called when the system needs memory and kills an application. It is not called when the user just closes the application. So I think application state should also be saved in onPause.

It should be saved to some persistent storage like Preferences or SQLite.

Both methods are useful and valid and both are best suited for different scenarios:

  1. The user terminates the application and re-opens it at a later date, but the application needs to reload data from the last session – this requires a persistent storage approach such as using SQLite.
  2. The user switches application and then comes back to the original and wants to pick up where they left off - save and restore bundle data (such as application state data) in onSaveInstanceState() and onRestoreInstanceState() is usually adequate.

If you save the state data in a persistent manner, it can be reloaded in an onResume() or onCreate() (or actually on any lifecycle call). This may or may not be desired behaviour. If you store it in a bundle in an InstanceState, then it is transient and is only suitable for storing data for use in the same user ‘session’ (I use the term session loosely) but not between ‘sessions’.

It is not that one approach is better than the other, like everything, it is just important to understand what behaviour you require and to select the most appropriate approach.

I think I found the answer. Let me tell what I have done in simple words:

Suppose I have two activities, activity1 and activity2 and I am navigating from activity1 to activity2 (I have done some works in activity2) and again back to activity 1 by clicking on a button in activity1. Now at this stage I wanted to go back to activity2 and I want to see my activity2 in the same condition when I last left activity2.

For the above scenario what I have done is that in the manifest I made some changes like this:

<activity android:name=".activity2"
          android:alwaysRetainTaskState="true"      
          android:launchMode="singleInstance">
</activity>

And in the activity1 on the button click event I have done like this:

Intent intent = new Intent();
intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
intent.setClassName(this,"com.mainscreen.activity2");
startActivity(intent);

And in activity2 on button click event I have done like this:

Intent intent=new Intent();
intent.setClassName(this,"com.mainscreen.activity1");
startActivity(intent);

Now what will happen is that whatever the changes we have made in the activity2 will not be lost, and we can view activity2 in the same state as we left previously.

I believe this is the answer and this works fine for me. Correct me if I am wrong.

onSaveInstanceState() for transient data (restored in onCreate()/onRestoreInstanceState()), onPause() for persistent data (restored in onResume()). From Android technical resources:

onSaveInstanceState() is called by Android if the Activity is being stopped and may be killed before it is resumed! This means it should store any state necessary to re-initialize to the same condition when the Activity is restarted. It is the counterpart to the onCreate() method, and in fact the savedInstanceState Bundle passed in to onCreate() is the same Bundle that you construct as outState in the onSaveInstanceState() method.

onPause() and onResume() are also complimentary methods. onPause() is always called when the Activity ends, even if we instigated that (with a finish() call for example). We will use this to save the current note back to the database. Good practice is to release any resources that can be released during an onPause() as well, to take up less resources when in the passive state.

My problem was that I needed persistence only during the application lifetime (i.e. a single execution including starting other sub-activities within the same app and rotating the device etc). I tried various combinations of the above answers but did not get what I wanted in all situations. In the end what worked for me was to obtain a reference to the savedInstanceState during onCreate:

mySavedInstanceState=savedInstanceState;

and use that to obtain the contents of my variable when I needed it, along the lines of:

if (mySavedInstanceState !=null) {
   boolean myVariable = mySavedInstanceState.getBoolean("MyVariable");
}

I use onSaveInstanceStateand onRestoreInstanceState as suggested above but I guess i could also or alternatively use my method to save the variable when it changes (e.g. using putBoolean)

When an activity is created it's onCreate() method is called.

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

savedInstanceState is an object of Bundle class which is null for the first time, but it contains values when it is recreated. To save Activity's state you have to override onSaveInstanceState().

   @Override
    protected void onSaveInstanceState(Bundle outState) {
      outState.putString("key","Welcome Back")
        super.onSaveInstanceState(outState);       //save state
    }

put your values in "outState" Bundle object like outState.putString("key","Welcome Back") and save by calling super. When activity will be destroyed it's state get saved in Bundle object and can be restored after recreation in onCreate() or onRestoreInstanceState(). Bundle received in onCreate() and onRestoreInstanceState() are same.

   @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
      //restore activity's state
     if(savedInstanceState!=null){
      String reStoredString=savedInstanceState.getString("key");
        }
}

or

  //restores activity's saved state
 @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
      String restoredMessage=savedInstanceState.getString("key");
    }
</div>