Android重新創(chuàng)建Activity

2018-08-02 18:34 更新

編寫:kesenhoo - 原文: http://developer.android.com/training/basics/activity-lifecycle/recreating.html

有幾個(gè)場(chǎng)景中,Activity是由于正常的程序行為而被Destory的。例如當(dāng)用戶點(diǎn)擊返回按鈕或者是Activity通過調(diào)用finish()來發(fā)出停止信號(hào)。系統(tǒng)也有可能會(huì)在Activity處于stop狀態(tài)且長(zhǎng)時(shí)間不被使用,或者是在前臺(tái)activity需要更多系統(tǒng)資源的時(shí)關(guān)閉后臺(tái)進(jìn)程,以圖獲取更多的內(nèi)存。

當(dāng)Activity是因?yàn)橛脩酎c(diǎn)擊Back按鈕或者是activity通過調(diào)用finish()結(jié)束自己時(shí),系統(tǒng)就丟失了對(duì)Activity實(shí)例的引用,因?yàn)檫@一行為意味著不再需要這個(gè)activity了。然而,如果因?yàn)橄到y(tǒng)資源緊張而導(dǎo)致Activity的Destory, 系統(tǒng)會(huì)在用戶回到這個(gè)Activity時(shí)有這個(gè)Activity存在過的記錄,系統(tǒng)會(huì)使用那些保存的記錄數(shù)據(jù)(描述了當(dāng)Activity被Destory時(shí)的狀態(tài))來重新創(chuàng)建一個(gè)新的Activity實(shí)例。那些被系統(tǒng)用來恢復(fù)之前狀態(tài)而保存的數(shù)據(jù)被叫做 "instance state" ,它是一些存放在Bundle對(duì)象中的key-value pairs。(請(qǐng)注意這里的描述,這對(duì)理解onSaveInstanceState執(zhí)行的時(shí)刻很重要)

Caution: 你的Activity會(huì)在每次旋轉(zhuǎn)屏幕時(shí)被destroyed與recreated。當(dāng)屏幕改變方向時(shí),系統(tǒng)會(huì)Destory與Recreate前臺(tái)的activity,因?yàn)槠聊慌渲帽桓淖?,你的Activity可能需要加載另一些替代的資源(例如layout).

默認(rèn)情況下, 系統(tǒng)使用 Bundle 實(shí)例來保存每一個(gè)View(視圖)對(duì)象中的信息(例如輸入EditText 中的文本內(nèi)容)。因此,如果Activity被destroyed與recreated, 則layout的狀態(tài)信息會(huì)自動(dòng)恢復(fù)到之前的狀態(tài)。然而,activity也許存在更多你想要恢復(fù)的狀態(tài)信息,例如記錄用戶Progress的成員變量(member variables)。

Note: 為了使Android系統(tǒng)能夠恢復(fù)Activity中的View的狀態(tài),每個(gè)View都必須有一個(gè)唯一ID,由android:id定義。

為了可以保存額外更多的數(shù)據(jù)到saved instance state。在Activity的生命周期里面存在一個(gè)額外的回調(diào)函數(shù),你必須重寫這個(gè)函數(shù)。該回調(diào)函數(shù)并沒有在前面課程的圖片示例中顯示。這個(gè)方法是onSaveInstanceState() ,當(dāng)用戶離開Activity時(shí),系統(tǒng)會(huì)調(diào)用它。當(dāng)系統(tǒng)調(diào)用這個(gè)函數(shù)時(shí),系統(tǒng)會(huì)在Activity被異常Destory時(shí)傳遞 Bundle 對(duì)象,這樣我們就可以增加額外的信息到Bundle中并保存到系統(tǒng)中。若系統(tǒng)在Activity被Destory之后想重新創(chuàng)建這個(gè)Activity實(shí)例時(shí),之前的Bundle對(duì)象會(huì)(系統(tǒng))被傳遞到你我們activity的onRestoreInstanceState()方法與 onCreate() 方法中。

basic-lifecycle-savestate

Figure 2. 當(dāng)系統(tǒng)開始停止Activity時(shí),只有在Activity實(shí)例會(huì)需要重新創(chuàng)建的情況下才會(huì)調(diào)用到onSaveInstanceState() (1) ,在這個(gè)方法里面可以指定額外的狀態(tài)數(shù)據(jù)到Bunde中。如果這個(gè)Activity被destroyed然后這個(gè)實(shí)例又需要被重新創(chuàng)建時(shí),系統(tǒng)會(huì)傳遞在 (1) 中的狀態(tài)數(shù)據(jù)到 onCreate() (2) 與 onRestoreInstanceState()(3).

(通常來說,跳轉(zhuǎn)到其他的activity或者是點(diǎn)擊Home都會(huì)導(dǎo)致當(dāng)前的activity執(zhí)行onSaveInstanceState,因?yàn)檫@種情況下的activity都是有可能會(huì)被destory并且是需要保存狀態(tài)以便后續(xù)恢復(fù)使用的,而從跳轉(zhuǎn)的activity點(diǎn)擊back回到前一個(gè)activity,那么跳轉(zhuǎn)前的activity是執(zhí)行退棧的操作,所以這種情況下是不會(huì)執(zhí)行onSaveInstanceState的,因?yàn)檫@個(gè)activity不可能存在需要重建的操作)

保存Activity狀態(tài)

當(dāng)我們的activity開始Stop,系統(tǒng)會(huì)調(diào)用 onSaveInstanceState() ,Activity可以用鍵值對(duì)的集合來保存狀態(tài)信息。這個(gè)方法會(huì)默認(rèn)保存Activity視圖的狀態(tài)信息,如在 EditText 組件中的文本或 ListView 的滑動(dòng)位置。

為了給Activity保存額外的狀態(tài)信息,你必須實(shí)現(xiàn)onSaveInstanceState() 并增加key-value pairs到 Bundle 對(duì)象中,例如:

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() 方法的父類實(shí)現(xiàn),這樣默認(rèn)的父類實(shí)現(xiàn)才能保存視圖狀態(tài)的信息。

恢復(fù)Activity狀態(tài)

當(dāng)Activity從Destory中重建,我們可以從系統(tǒng)傳遞的Activity的Bundle中恢復(fù)保存的狀態(tài)。 onCreate() 與 onRestoreInstanceState() 回調(diào)方法都接收到了同樣的Bundle,里面包含了同樣的實(shí)例狀態(tài)信息。

由于 onCreate() 方法會(huì)在第一次創(chuàng)建新的Activity實(shí)例與重新創(chuàng)建之前被Destory的實(shí)例時(shí)都被調(diào)用,我們必須在嘗試讀取 Bundle 對(duì)象前檢測(cè)它是否為null。如果它為null,系統(tǒng)則是創(chuàng)建一個(gè)新的Activity實(shí)例,而不是恢復(fù)之前被Destory的Activity。

下面是一個(gè)示例:演示在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
    }
    ...
}

我們也可以選擇實(shí)現(xiàn) onRestoreInstanceState() ,而不是在onCreate方法里面恢復(fù)數(shù)據(jù)。 onRestoreInstanceState()方法會(huì)在 onStart() 方法之后執(zhí)行. 系統(tǒng)僅僅會(huì)在存在需要恢復(fù)的狀態(tài)信息時(shí)才會(huì)調(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()方法的父類實(shí)現(xiàn),這樣默認(rèn)的父類實(shí)現(xiàn)才能保存視圖狀態(tài)的信息。更多關(guān)于運(yùn)行時(shí)狀態(tài)改變引起的recreate我們的activity。請(qǐng)參考Handling Runtime Changes.


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)