使用"保存实例状态"保存Android活动状态
我一直在使用Android SDK平台,但尚不清楚如何保存应用程序的状态。因此,对" Hello,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分钟左右的时间,并且没有发现任何明显的问题。
解决方案
" savedInstanceState"仅用于保存与Activity的当前实例相关联的状态,例如当前的导航或者选择信息,因此,如果Android销毁并重新创建Activity,它可以像以前一样返回。请参阅有关onCreate和onSaveInstanceState的文档
对于更长的状态,请考虑使用SQLite数据库,文件或者首选项。请参阅保存持久状态。
我们需要覆盖onSaveInstanceState(Bundle savedInstanceState)
并将要更改的应用程序状态值写到Bundle
参数,如下所示:
@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. }
Bundle本质上是一种存储NVP("名称-值对")映射的方式,它将被传递给onCreate()和onRestoreInstanceState(),我们可以在其中提取值,如下所示:
@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"); }
通常,我们将使用此技术来存储应用程序的实例值(选择,未保存的文本等)。
当系统需要内存并杀死应用程序时,将调用onSaveInstanceState。当用户只是关闭应用程序时,不会调用它。所以我认为应用程序状态也应该保存在onPause中,并且应该保存到一些持久性存储中,例如Preferences或者Sqlite。
当Activity进入后台时,真正的onSaveInstance
状态被调用
从文档引用:
"在将活动置于这样的背景状态之前,将调用方法onSaveInstanceState(Bundle)
。"
请注意,根据http://developer.android.com/reference/android/app/Activity.html中有关"活动状态"的文档,对持久性数据使用onSaveInstanceState
和onRestoreInstanceState
是不安全的。
该文档指出(在"活动生命周期"部分中):
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.
换句话说,将持久性数据的保存/恢复代码放在onPause()和onResume()中!
编辑:为进一步澄清,这是onSaveInstanceState()
文档:
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).
我的同事写了一篇文章,解释了Android设备上的应用程序状态,包括有关活动生命周期和状态信息,如何存储状态信息以及如何保存到状态" Bundle"和" SharedPreferences"的说明,并在此处进行了介绍。
本文介绍了三种方法:
使用实例状态包存储本地变量/ UI控制数据,以保持应用程序生存期(即临时)
[Code sample – Store State in State Bundle] @Override public void onSaveInstanceState(Bundle savedInstanceState) { // Store UI state to the savedInstanceState. // This bundle will be passed to onCreate on next call. EditText txtName = (EditText)findViewById(R.id.txtName); String strName = txtName.getText().toString(); EditText txtEmail = (EditText)findViewById(R.id.txtEmail); String strEmail = txtEmail.getText().toString(); CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC); boolean blnTandC = chkTandC.isChecked(); savedInstanceState.putString(“Name”, strName); savedInstanceState.putString(“Email”, strEmail); savedInstanceState.putBoolean(“TandC”, blnTandC); super.onSaveInstanceState(savedInstanceState); }
使用共享首选项在应用程序实例之间(即永久)存储本地变量/ UI控制数据
[Code sample – Store State in SharedPreferences] @Override protected void onPause() { super.onPause(); // Store values between instances here SharedPreferences preferences = getPreferences(MODE_PRIVATE); SharedPreferences.Editor editor = preferences.edit(); // Put the values from the UI EditText txtName = (EditText)findViewById(R.id.txtName); String strName = txtName.getText().toString(); EditText txtEmail = (EditText)findViewById(R.id.txtEmail); String strEmail = txtEmail.getText().toString(); CheckBox chkTandC = (CheckBox)findViewById(R.id.chkTandC); boolean blnTandC = chkTandC.isChecked(); editor.putString(“Name”, strName); // value to store editor.putString(“Email”, strEmail); // value to store editor.putBoolean(“TandC”, blnTandC); // value to store // Commit to storage editor.commit(); }
使用保留的非配置实例使对象实例在应用程序生存期内的活动之间的内存中保持活动状态
[Code sample – store object instance] private cMyClassType moInstanceOfAClass;// Store the instance of an object @Override public Object onRetainNonConfigurationInstance() { if (moInstanceOfAClass != null) // Check that the object exists return(moInstanceOfAClass); return super.onRetainNonConfigurationInstance(); }