比较onsaveinstancestate() 与 onretainnonconfigurationinstance()在不同需求中的用法
很多网友可能知道android横竖屏切换时会触发onsaveinstancestate,而还原时会产生onrestoreinstancestate,但是android的activity类还有一个方法名为onretainnonconfigurationinstance和getlastnonconfigurationinstance这两个方法。

我们可以通过 onretainnonconfigurationinstance 代替 onsaveinstancestate,比如距离2

@override
public object onretainnonconfigurationinstance()
{
//这里需要保存的内容,在切换时不是bundle了,我们可以直接通过object来代替
return obj;
}

在恢复窗口时,我们可以不使用 onrestoreinstancestate,而代替的是 getlastnonconfigurationinstance 方法。我们可以直接在oncreate中使用,比如

object obj = getlastnonconfigurationinstance(); 最终obj的内容就是上次切换时的内容。
针对android平台,不论出于哪种目的,都或多或少需要在多个activities中的跳转操作,其中包括为了获得某些系统资源和必要信息,而通过启动(startactivity()&startactivityforresult() )child activity来提供一个选择器或者作为用户输入信息的介质。这期间父级activity将暂时性失去焦点,从而在这之前先通过 onsaveinstancestate() 方法临时存储一些必要的信息,当父级的activity重新成为当前焦点后,系统将触发 onrestoreinstancestate() 恢复失去焦点前的原有数据!onretainnonconfigurationinstance()也具有相同的目的来处理类似的请求,其主要是由于旋转设备而更改显示模式,进而触发这个方法的调用。

那么在遇到某些特定需求时,特别是针对设备旋转后所导致的显示模式发生变化后,应该依据什么条件来判断应用哪种方式才能更好的满足需要呢?做出选择之前有必要分别了解两种方法的各自特点。

onsaveinstancestate()

在当前的activity中通过新的intent启动其它activities之后,它将通过这个方法自动保存自身的数据,当再次出返回时可以通过 onrestoreinstancestate()复原数据。另外一种情况也将调用这个方法,当旋转设备后屏幕显示模式发生改变时。需要注意的一点是整个过程完全由系统控制,无法通过onsaveinstancestate()返回一个自定义的数据。

另外,onsaveinstancestate()在所有activity destroying过程中被调用,它仅仅是为了在重新回到这个特定的activity之后,依据activity state重新创建一个与之前状态完全相同的activity。例如:当我们启动某些connection时,state并不能依然保存这个连接状态。所以当调用onsaveinstancestate后,所有当前的connection将一同销毁。当第二次通过 onrestoreinstancestate()找回之前的连接设置并重新建立新的连接实体。

如果大家有更多的发现,或者有不用于以上的验证结果,非常感谢能参与这个话题的讨论。

onretainnonconfigurationinstance()

当device configuration发生改变时,将伴随destroying被系统调用。通过这个方法可以像onsaveinstancestate()的方法一样保留变化前的activity state,最大的不同在于这个方法可以返回一个包含有状态信息的object,其中甚至可以包含activity instance本身。新创建的activity可以继承大量来至于parent activity state信息。

用这个方法保存activity state后,通过getlastnonconfigurationinstance()在新的activity instance中恢复原有状态。

这个方法最大的好处是:

* 当activity曾经通过某个网络资源得到一些图片或者视频信息,那么当再次恢复后,无需重新通过原始资源地址获取,可以快速的加载整个activity状态信息。

* 当activity包含有许多线程时,在变化后依然可以持有原有线程,无需通过重新创建进程恢复原有状态。

* 当activity包含某些connection instance时,同样可以在整个变化过程中保持连接状态。

下边是需要特别注意的几点:

* onretainnonconfigurationinstance()在onsaveinstancestate()之后被调用。
* 调用顺序同样介于onstop() 和 ondestroy()之间。

接下来将通过一个例子来简单了解onretainnonconfigurationinstance()和getlastnonconfigurationinstance()的用法。

这个例子将首先启动一个包含两个按钮的activity。其中一个按钮用于调用本地通讯录,并将所选择的某一项作为返回值传给当前 activity。另外一个按钮的作用是查看当前所选择的通讯信息。正常的流程是当第一次启动程序后,第二个查看信息按钮是不可用状态。当通过pick按钮确定选择并返回某一通讯录内容时,查看信息按钮的状态切换为可操作状态。然后当改变设备的configuration时,可以注意到即便是 activity通过oncreate()重新构建,但是之前所保证的ui属性依然保持最后一次操作的状态。

简单建立一个包含两个按钮的ui:
?view code xml

<linearlayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<button android:id="@+id/pick"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1"
android:text="pick"
android:enabled="true"
/>
如果你想保存Activity的信息(例如,类实例的变量)而又不需要和其它的组件共享的话,你可以调用ActivitygetPreferences方法,不用指定一个Preference的名字。对返回的Shared Preference的访问只限于调用的Activity;每个Activity支持一个不命名的Shared Preference对象。

下面的框架代码显示了如何使用Activity的私有Shared Preference

protected void saveActivityPreferences()
{
// Create or retrieve the activity preferences object.
SharedPreferences activityPreferences =getPreferences(Activity.MODE_PRIVATE);

// Retrieve an editor to modify the shared preferences.
SharedPreferences.Editor editor = activityPreferences.edit();

// Retrieve the View
TextView myTextView = (TextView)findViewById(R.id.myTextView);

// Store new primitive types in the shared preferences object.
editor.putString(“currentTextValue”,myTextView.getText().toString());

// Commit changes.
editor.commit();
}

保存和恢复实例状态

对于保存Activity实例的变量来说,Android提供了一种替代Shared Preference的特殊方法。

通过重写ActivityonSaveInstanceState事件处理函数,你可以使用它的Bundle参数来保存实例的值。保存数据的方法还是使用与在Shared Preference中相同的getput方法。在完成Bundle的修改后,将其传入父类的处理函数中,如下面的代码片段所示:

private static final String TEXTVIEW_STATE_KEY = “TEXTVIEW_STATE_KEY”;
@Override
public void onSaveInstanceState(Bundle outState) {
// Retrieve the View
TextView myTextView = (TextView)findViewById(R.id.myTextView);

// Save its state
outState.putString(TEXTVIEW_STATE_KEY,
myTextView.getText().toString());

super.onSaveInstanceState(outState);
}

这个处理函数会在ActivityActive生命周期结束时触发,但仅在它不是显式地结束(即异常结束)。因此,它一般用于确保在单个用户会话中的Active生命周期间Activity状态的一致性。

如果一个会话期间,应用程序被迫重启,那么,保存的Bundle会传入到onRestoreInstanceStateonCreate方法中。下面的片段显示了如何从Bundle中提取值来更新Activity实例的状态:

@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.main);
TextView myTextView = (TextView)findViewById(R.id.myTextView);
String text = “”;
if (icicle != null && icicle.containsKey(TEXTVIEW_STATE_KEY))
text = icicle.getString(TEXTVIEW_STATE_KEY);
myTextView.setText(text);
}

有一点很重要的是,记住onSaveInstanceState仅在Activity变成非Active状态时调用,但不在调用finish来关闭它或用户按下Back按钮时调用。

保存To-Do List Activity的状态

目前,每一次To-Do List例子程序重新启动时,所有的to-do项都丢失了且任何在文本输入框中输入的文字也被清除了。在这个例子中,你将在会话期间保存To-Do List程序的状态。

ToDoList Activity中的实例状态由三个变量组成:

是否一个新的Item正在添加?

在新的项目输入框中存在什么样的文字?

哪个是当前选择的项目?

使用Activity默认的Shared Preference,你可以保存这些值,当Activity重启时更新UI

在本章的后面,你将学习如何使用SQLite去保存to-do项目。这个例子是第一步,演示如何通过保持Activity实例的细节来确保无瑕疵的体验。

1. 添加静态的字符串用作Preference的键。

private static final String TEXT_ENTRY_KEY = “TEXT_ENTRY_KEY”;
private static final String ADDING_ITEM_KEY = “ADDING_ITEM_KEY”;
private static final String SELECTED_INDEX_KEY = “SELECTED_INDEX_KEY”;

2. 接下来,重写onPause方法。获得Activity的私有Shared Preference并得到它的Editor对象。

使用第1步中创建的键,存储实例的值,包括是否一个新的项目正在添加和任何在“new item”输入框中的文本。

@Override
protected void onPause(){
super.onPause();

// Get the activity preferences object.
SharedPreferences uiState = getPreferences(0);

// Get the preferences editor.
SharedPreferences.Editor editor = uiState.edit();

// Add the UI state preference values.
editor.putString(TEXT_ENTRY_KEY, myEditText.getText().toString());
editor.putBoolean(ADDING_ITEM_KEY, addingNew);

// Commit the preferences.
editor.commit();
}

3. 编写一个restoreUIState方法,当程序重启时,应用在第2步中记录的实例的值。

修改onCreate方法,在最后部分添加对restoreUIState方法的调用。

@Override
public void onCreate(Bundle icicle)
{
[ ... existing onCreate logic ... ]
restoreUIState();
}

private void restoreUIState()
{
// Get the activity preferences object.
SharedPreferences settings = getPreferences(Activity.MODE_PRIVATE);

// Read the UI state values, specifying default values.
String text = settings.getString(TEXT_ENTRY_KEY, “”);
Boolean adding = settings.getBoolean(ADDING_ITEM_KEY, false);

// Restore the UI to the previous state.
if (adding)
{
addNewItem();
myEditText.setText(text);
}
}

4. 使用onSaveInstanceState/onRestoreInstanceState机制来记录当前选择的项目的索引。它仅在非用户显式的指令杀死应用程序时保存和应用。

@Override
public void onSaveInstanceState(Bundle outState)
{
outState.putInt(SELECTED_INDEX_KEY,myListView.getSelectedItemPosition());
super.onSaveInstanceState(outState);
}

@Override
public void onRestoreInstanceState(Bundle savedInstanceState)
{
int pos = -1;
if (savedInstanceState != null)
if (savedInstanceState.containsKey(SELECTED_INDEX_KEY))
pos = savedInstanceState.getInt(SELECTED_INDEX_KEY, -1);
myListView.setSelection(pos);
}

当你运行To-Do List程序时,你应该看到了在会话期间UI状态的保存。但是,它还不能保存to-do列表的项目——你将在本章的后面添加这个核心的功能。

更多相关文章

  1. Android发送短信方法实例详解
  2. Android 读取资源文件实例详解
  3. Android 旋转屏幕捕获当前屏幕的状态
  4. Android 用sp存储登录状态以及退出登录
  5. android 解析 xml 文档的三种方法
  6. 几个Android小错误解决方法
  7. android读取assets大于1M文件的解决方法
  8. android中的状态保存
  9. 检测Android设备有线网络连接状态

随机推荐

  1. android audio
  2. Android——截图案例
  3. Android(安卓)Code Style Rules
  4. android之RecycleView适配器添加点击事件
  5. Android版本号的识别——$(PLATFORM_VERS
  6. android中popupwindow的点滴
  7. android导入项目遇到的问题
  8. Android(安卓)Touch事件分发机制学习
  9. Android-->build.gradle-->packagingOpti
  10. Android(安卓)计算器界面的实现