How to save an activity state using save instance

2020-01-22 11:01发布

I've been working on the Android SDK platform, and it is a little unclear how to save an application's state. So given this minor re-tooling of the 'Hello, Android' example:

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);
  }
}

I thought it would be enough for the simplest case, but it always responds with the first message, no matter how I navigate away from the app.

I'm sure the solution is as simple as overriding onPause or something like that, but I've been poking away in the documentation for 30 minutes or so and haven't found anything obvious.

30条回答
我命由我不由天
2楼-- · 2020-01-22 11:33

Kotlin code:

save:

override fun onSaveInstanceState(outState: Bundle) {
    super.onSaveInstanceState(outState.apply {
        putInt("intKey", 1)
        putString("stringKey", "String Value")
        putParcelable("parcelableKey", parcelableObject)
    })
}

and then in onCreate() or onRestoreInstanceState()

    val restoredInt = savedInstanceState?.getInt("intKey") ?: 1 //default int
    val restoredString = savedInstanceState?.getString("stringKey") ?: "default string"
    val restoredParcelable = savedInstanceState?.getParcelable<ParcelableClass>("parcelableKey") ?: ParcelableClass() //default parcelable

Add default values if you don't want to have Optionals

查看更多
Emotional °昔
3楼-- · 2020-01-22 11:34

The savedInstanceState is only for saving state associated with a current instance of an Activity, for example current navigation or selection info, so that if Android destroys and recreates an Activity, it can come back as it was before. See the documentation for onCreate and onSaveInstanceState

For more long lived state, consider using a SQLite database, a file, or preferences. See Saving Persistent State.

查看更多
我欲成王,谁敢阻挡
4楼-- · 2020-01-22 11:34

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.

查看更多
不美不萌又怎样
5楼-- · 2020-01-22 11:34

Really onSaveInstanceState() is called when the Activity goes to background.

Quote from the docs: "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." Source

查看更多
我命由我不由天
6楼-- · 2020-01-22 11:36

What to save and what not to?

Ever wondered why the text in the EditText gets saved automatically while an orientation change? Well, this answer is for you.

When an instance of an Activity gets destroyed and the System recreates a new instance (for example, configuration change). It tries to recreate it using a set of saved data of old Activity State (instance state).

Instance state is a collection of key-value pairs stored in a Bundle object.

By default System saves the View objects in the Bundle for example.

  • Text in EditText
  • Scroll position in a ListView, etc.

If you need another variable to be saved as a part of instance state you should OVERRIDE onSavedInstanceState(Bundle savedinstaneState) method.

For example, int currentScore in a GameActivity

More detail about the onSavedInstanceState(Bundle savedinstaneState) while saving data

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

So by mistake if you forget to call super.onSaveInstanceState(savedInstanceState);the default behavior will not work ie Text in EditText will not save.

Which to choose for restoring Activity state?

 onCreate(Bundle savedInstanceState)

OR

onRestoreInstanceState(Bundle savedInstanceState)

Both methods get the same Bundle object, so it does not really matter where you write your restoring logic. The only difference is that in onCreate(Bundle savedInstanceState) method you will have to give a null check while it is not needed in the latter case. Other answers have already code snippets. You can refer them.

More detail about the onRestoreInstanceState(Bundle savedinstaneState)

@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from the saved instance
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
}

Always call super.onRestoreInstanceState(savedInstanceState); so that System restore the View hierarchy by default

Bonus

The onSaveInstanceState(Bundle savedInstanceState) is invoked by the system only when the user intends to come back to the Activity. For example, you are using App X and suddenly you get a call. You move to the caller app and come back to the app X. In this case the onSaveInstanceState(Bundle savedInstanceState) method will be invoked.

But consider this if a user presses the back button. It is assumed that the user does not intend to come back to the Activity, hence in this case onSaveInstanceState(Bundle savedInstanceState) will not be invoked by the system. Point being you should consider all the scenarios while saving data.

Relevant links:

Demo on default behavior
Android Official Documentation.

查看更多
别忘想泡老子
7楼-- · 2020-01-22 11:36

you can use the Live Data and View Model For Lifecycle Handel From JetPack. see this Reference :

https://developer.android.com/topic/libraries/architecture/livedata

查看更多
登录 后发表回答