編寫:kesenhoo - 原文: http://developer.android.com/training/basics/activity-lifecycle/recreating.html
有幾個場景中,Activity是由于正常的程序行為而被Destory的。例如當(dāng)用戶點(diǎn)擊返回按鈕或者是Activity通過調(diào)用finish()來發(fā)出停止信號。系統(tǒng)也有可能會在Activity處于stop狀態(tài)且長時間不被使用,或者是在前臺activity需要更多系統(tǒng)資源的時關(guān)閉后臺進(jìn)程,以圖獲取更多的內(nèi)存。
當(dāng)Activity是因為用戶點(diǎn)擊Back按鈕或者是activity通過調(diào)用finish()結(jié)束自己時,系統(tǒng)就丟失了對Activity實例的引用,因為這一行為意味著不再需要這個activity了。然而,如果因為系統(tǒng)資源緊張而導(dǎo)致Activity的Destory, 系統(tǒng)會在用戶回到這個Activity時有這個Activity存在過的記錄,系統(tǒng)會使用那些保存的記錄數(shù)據(jù)(描述了當(dāng)Activity被Destory時的狀態(tài))來重新創(chuàng)建一個新的Activity實例。那些被系統(tǒng)用來恢復(fù)之前狀態(tài)而保存的數(shù)據(jù)被叫做 "instance state" ,它是一些存放在Bundle對象中的key-value pairs。(請注意這里的描述,這對理解onSaveInstanceState執(zhí)行的時刻很重要)
Caution: 你的Activity會在每次旋轉(zhuǎn)屏幕時被destroyed與recreated。當(dāng)屏幕改變方向時,系統(tǒng)會Destory與Recreate前臺的activity,因為屏幕配置被改變,你的Activity可能需要加載另一些替代的資源(例如layout).
默認(rèn)情況下, 系統(tǒng)使用 Bundle 實例來保存每一個View(視圖)對象中的信息(例如輸入EditText 中的文本內(nèi)容)。因此,如果Activity被destroyed與recreated, 則layout的狀態(tài)信息會自動恢復(fù)到之前的狀態(tài)。然而,activity也許存在更多你想要恢復(fù)的狀態(tài)信息,例如記錄用戶Progress的成員變量(member variables)。
Note: 為了使Android系統(tǒng)能夠恢復(fù)Activity中的View的狀態(tài),每個View都必須有一個唯一ID,由android:id定義。
為了可以保存額外更多的數(shù)據(jù)到saved instance state。在Activity的生命周期里面存在一個額外的回調(diào)函數(shù),你必須重寫這個函數(shù)。該回調(diào)函數(shù)并沒有在前面課程的圖片示例中顯示。這個方法是onSaveInstanceState() ,當(dāng)用戶離開Activity時,系統(tǒng)會調(diào)用它。當(dāng)系統(tǒng)調(diào)用這個函數(shù)時,系統(tǒng)會在Activity被異常Destory時傳遞 Bundle 對象,這樣我們就可以增加額外的信息到Bundle中并保存到系統(tǒng)中。若系統(tǒng)在Activity被Destory之后想重新創(chuàng)建這個Activity實例時,之前的Bundle對象會(系統(tǒng))被傳遞到你我們activity的onRestoreInstanceState()方法與 onCreate() 方法中。
http://wiki.jikexueyuan.com/project/android-training-geek/images/basic-lifecycle-savestate.png" alt="basic-lifecycle-savestate" />
Figure 2. 當(dāng)系統(tǒng)開始停止Activity時,只有在Activity實例會需要重新創(chuàng)建的情況下才會調(diào)用到onSaveInstanceState() (1) ,在這個方法里面可以指定額外的狀態(tài)數(shù)據(jù)到Bunde中。如果這個Activity被destroyed然后這個實例又需要被重新創(chuàng)建時,系統(tǒng)會傳遞在 (1) 中的狀態(tài)數(shù)據(jù)到 onCreate() (2) 與 onRestoreInstanceState()(3).
(通常來說,跳轉(zhuǎn)到其他的activity或者是點(diǎn)擊Home都會導(dǎo)致當(dāng)前的activity執(zhí)行onSaveInstanceState,因為這種情況下的activity都是有可能會被destory并且是需要保存狀態(tài)以便后續(xù)恢復(fù)使用的,而從跳轉(zhuǎn)的activity點(diǎn)擊back回到前一個activity,那么跳轉(zhuǎn)前的activity是執(zhí)行退棧的操作,所以這種情況下是不會執(zhí)行onSaveInstanceState的,因為這個activity不可能存在需要重建的操作)
當(dāng)我們的activity開始Stop,系統(tǒng)會調(diào)用 onSaveInstanceState() ,Activity可以用鍵值對的集合來保存狀態(tài)信息。這個方法會默認(rèn)保存Activity視圖的狀態(tài)信息,如在 EditText 組件中的文本或 ListView 的滑動位置。
為了給Activity保存額外的狀態(tài)信息,你必須實現(xiàn)onSaveInstanceState() 并增加key-value pairs到 Bundle 對象中,例如:
static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
// Save the user's current game state
savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
// Always call the superclass so it can save the view hierarchy state
super.onSaveInstanceState(savedInstanceState);
}
Caution: 必須要調(diào)用 onSaveInstanceState() 方法的父類實現(xiàn),這樣默認(rèn)的父類實現(xiàn)才能保存視圖狀態(tài)的信息。
當(dāng)Activity從Destory中重建,我們可以從系統(tǒng)傳遞的Activity的Bundle中恢復(fù)保存的狀態(tài)。 onCreate() 與 onRestoreInstanceState() 回調(diào)方法都接收到了同樣的Bundle,里面包含了同樣的實例狀態(tài)信息。
由于 onCreate() 方法會在第一次創(chuàng)建新的Activity實例與重新創(chuàng)建之前被Destory的實例時都被調(diào)用,我們必須在嘗試讀取 Bundle 對象前檢測它是否為null。如果它為null,系統(tǒng)則是創(chuàng)建一個新的Activity實例,而不是恢復(fù)之前被Destory的Activity。
下面是一個示例:演示在onCreate方法里面恢復(fù)一些數(shù)據(jù):
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); // Always call the superclass first
// Check whether we're recreating a previously destroyed instance
if (savedInstanceState != null) {
// Restore value of members from saved state
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
} else {
// Probably initialize members with default values for a new instance
}
...
}
我們也可以選擇實現(xiàn) onRestoreInstanceState() ,而不是在onCreate方法里面恢復(fù)數(shù)據(jù)。 onRestoreInstanceState()方法會在 onStart() 方法之后執(zhí)行. 系統(tǒng)僅僅會在存在需要恢復(fù)的狀態(tài)信息時才會調(diào)用 onRestoreInstanceState() ,因此不需要檢查 Bundle 是否為null。
public void onRestoreInstanceState(Bundle savedInstanceState) {
// Always call the superclass so it can restore the view hierarchy
super.onRestoreInstanceState(savedInstanceState);
// Restore state members from saved instance
mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}
Caution: 與上面保存一樣,總是需要調(diào)用onRestoreInstanceState()方法的父類實現(xiàn),這樣默認(rèn)的父類實現(xiàn)才能保存視圖狀態(tài)的信息。更多關(guān)于運(yùn)行時狀態(tài)改變引起的recreate我們的activity。請參考Handling Runtime Changes。