activity狀態的保存和保持(onRetainNonConfigurationInstance和getLastNonConfigurationInstanc

比較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的信息(例如,類實例的變量)而又不須要和其它的組件共享的話,你能夠調用Activity的getPreferences方法,不用指定一個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的特殊方法。

經過重寫Activity的onSaveInstanceState事件處理函數,你可使用它的Bundle參數來保存實例的值。保存數據的方法仍是使用與在Shared Preference中相同的get和put方法。在完成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);
}

這個處理函數會在Activity的Active生命週期結束時觸發,但僅在它不是顯式地結束(即異常結束)。所以,它通常用於確保在單個用戶會話中的Active生命週期間Activity狀態的一致性。

若是一個會話期間,應用程序被迫重啓,那麼,保存的Bundle會傳入到onRestoreInstanceState和onCreate方法中。下面的片斷顯示瞭如何從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列表的項目——你將在本章的後面添加這個核心的功能。android

相關文章
相關標籤/搜索