天天看點

Activity的生命周期、BACK鍵和HOME鍵生命周期

Activity的生命周期模型在Google提供的官方文檔上有比較詳細的一個圖示

Activity的生命周期、BACK鍵和HOME鍵生命周期
Activity的生命周期、BACK鍵和HOME鍵生命周期
public class HelloActivity extends Activity {
    public static final String TAG = "HelloActivity";
    /** 
     * 第一個被運作的方法
     * 初始化頁面
     * Bundle恢複上次的狀态 
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Log.v(TAG, "onCreate");
    }
    
    /**
     * 從onStop回到Activity的時候會執行
     * 按HOME鍵的時候會執行onStop,重新回到程式會執行這個方法
     */
    @Override
    protected void onRestart() {
        super.onRestart();
        Log.v(TAG, "onRestart");
    }
    
    /**
     * 在onCreate,onRestart後面執行
     */
    @Override
       protected void onStart() {
           super.onStart();
           Log.v(TAG, "onStart");
       }
    
    /**
     * 在onStart後面執行,執行這個方法後這個Activity就處于全部Activity堆棧的最上面
     * 進入使用者可見可操作的狀态
     */
    @Override
    protected void onResume() {
        super.onResume();
        Log.v(TAG, "onResume");
    }
    
    /**
     * 當其他Activity啟動時這個方法會執行
     * 按HOME和BACK都會執行這個方法
     * 最好在這個方法中送出或者儲存資料,因為很有可能再也不會回到這個activity中。
     * 這個方法最好不要執行太長時間,因為下個activity開始執行前會等待這個方法傳回。
     */
    @Override
    protected void onPause() {
        super.onPause();
        Log.v(TAG, "onPause");
    }

    /**
     * activity很久沒被顯示,要被銷毀,系統資源缺乏,都會調用這個方法
     * 按HOME和BACK都會執行這個方法
     */
    @Override
    protected void onStop() {
        super.onStop();
        Log.v(TAG, "onStop");
    }

    /**
     * 調用finish方法,或者系統回收資源時調用
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.v(TAG, "onDestroy");
    }
    
}      
Activity的生命周期、BACK鍵和HOME鍵生命周期

PS:

  •  手機應用的大多數情況下我們隻能在手機上看到一個程式的一個界面,使用者除了通過程式界面上的功能按鈕來在不同的窗體間切換,還可以通過Back鍵和 Home鍵來傳回上一個視窗,而使用者使用Back或者Home的時機是非常不确定的,任何時候使用者都可以使用Home或Back來強行切換目前的界面。
  • HOME鍵的執行順序:onPause->onStop->onRestart->onStart->onResume
  • BACK鍵的順序: onPause->onStop->onDestroy->onCreate->onStart->onResume
  • onPause不要做太耗時的工作

    各種方法的詳解

    1. void onCreate(Bundle savedInstanceState) 

    當Activity被第首次加載時執行。我們新啟動一個程式的時候其主窗體的onCreate事件就會被執行。如果Activity被銷毀後 (onDestroy後),再重新加載進Task時,其onCreate事件也會被重新執行。注意這裡的參數 savedInstanceState(Bundle類型是一個鍵值對集合,大家可以看成是.Net中的Dictionary)是一個很有用的設計,由于 前面已經說到的手機應用的特殊性,一個Activity很可能被強制交換到背景(交換到背景就是指該窗體不再對使用者可見,但實際上又還是存在于某個 Task中的,比如一個新的Activity壓入了目前的Task進而“遮蓋”住了目前的 Activity,或者使用者按了Home鍵回到桌面,又或者其他重要事件發生導緻新的Activity出現在目前Activity之上,比如來電界面), 而如果此後使用者在一段時間内沒有重新檢視該窗體(Android通過長按Home鍵可以選擇最近運作的6個程式,或者使用者直接再次點選程式的運作圖示,如 果窗體所在的Task和程序沒有被系統銷毀,則不用重新加載Process, Task和Task中的Activity,直接重新顯示Task頂部的Activity,這就稱之為重新檢視某個程式的窗體),該窗體連同其所在的 Task和Process則可能已經被系統自動銷毀了,此時如果再次檢視該窗體,則要重新執行 onCreate事件初始化窗體。而這個時候我們可能希望使用者繼續上次打開該窗體時的操作狀态進行操作,而不是一切從頭開始。例如使用者在編輯短信時突然來 電,接完電話後使用者又去做了一些其他的事情,比如儲存來電号碼到聯系人,而沒有立即回到短信編輯界面,導緻了短信編輯界面被銷毀,當使用者重新進入短信程式 時他可能希望繼續上次的編輯。這種情況我們就可以覆寫Activity的void onSaveInstanceState(Bundle outState)事件,通過向outState中寫入一些我們需要在窗體銷毀前儲存的狀态或資訊,這樣在窗體重新執行onCreate的時候,則會通過 savedInstanceState将之前儲存的資訊傳遞進來,此時我們就可以有選擇的利用這些資訊來初始化窗體,而不是一切從頭開始。 

    2. void onStart() 

    onCreate事件之後執行。或者目前窗體被交換到背景後,在使用者重新檢視窗體前已經過去了一段時間,窗體已經執行了onStop事件,但是窗 體和其所在程序并沒有被銷毀,使用者再次重新檢視窗體時會執行onRestart事件,之後會跳過onCreate事件,直接執行窗體的onStart事 件。 

    3. void onResume() 

    onStart事件之後執行。或者目前窗體被交換到背景後,在使用者重新檢視窗體時,窗體還沒有被銷毀,也沒有執行過onStop事件(窗體還繼續存在于Task中),則會跳過窗體的onCreate和onStart事件,直接執行onResume事件。 

    4. void onPause() 

    窗體被交換到背景時執行。 

    5. void onStop() 

    onPause事件之後執行。如果一段時間内使用者還沒有重新檢視該窗體,則該窗體的onStop事件将會被執行;或者使用者直接按了Back鍵,将該窗體從目前Task中移除,也會執行該窗體的onStop事件。 

    6. void onRestart() 

    onStop事件執行後,如果窗體和其所在的程序沒有被系統銷毀,此時使用者又重新檢視該窗體,則會執行窗體的onRestart事件,onRestart事件後會跳過窗體的onCreate事件直接執行onStart事件。 

    7. void onDestroy() 

    Activity被銷毀的時候執行。在窗體的onStop事件之後,如果沒有再次檢視該窗體,Activity則會被銷毀。 

    最後用一個實際的例子來說明Activity的各個生命周期。假設有一個程式由2個Activity A和B組成,A是這個程式的啟動界面。當使用者啟動程式時,Process和預設的Task分别被建立,接着A被壓入到目前的Task中,依次執行了 onCreate, onStart, onResume事件被呈現給了使用者;此時使用者選擇A中的某個功能開啟界面B,界面B被壓入目前Task遮蓋住了A,A的onPause事件執行,B的 onCreate, onStart, onResume事件執行,呈現了界面B給使用者;使用者在界面B操作完成後,使用Back鍵回到界面A,界面B不再可見,界面B的onPause, onStop, onDestroy執行,A的onResume事件被執行,呈現界面A給使用者。此時突然來電,界面A的onPause事件被執行,電話接聽界面被呈現給用 戶,使用者接聽完電話後,又按了Home鍵回到桌面,打開另一個程式“聯系人”,添加了聯系人資訊又做了一些其他的操作,此時界面A不再可見,其 onStop事件被執行,但并沒有被銷毀。此後使用者重新從菜單中點選了我們的程式,由于A和其所在的程序和Task并沒有被銷毀,A的onRestart 和onStart事件被執行,接着A的onResume事件被執行,A又被呈現給了使用者。使用者這次使用完後,按Back鍵傳回到桌面,A的 onPause, onStop被執行,随後A的onDestroy被執行,由于目前Task中已經沒有任何Activity,A所在的Process的重要程度被降到很 低,很快A所在的Process被系統結束

    常見的例子

情形一、一個單獨的Activity的正常的生命過程是這樣的:onCreate->onStart->onPause->onStop->onDestroy。例如:運作一個Activity,進行了一些簡單操作(不涉及頁面的跳轉等),然後按傳回鍵結束。

情形二、有兩個Activity(a和b),一開始顯示a,然後由a啟動b,然後在由b回到a,這時候a的生命過程應該是怎麼樣的呢(a被b完全遮蓋)?

a經曆的過程為onCreate->onStart->onResume->onPause->onStop->onRestart->onStart->onResume。這個過程說明了圖中,如果Activity完全被其他界面遮擋時,進入背景,并沒有完全銷毀,而是停留在onStop狀态,當再次進入a時,onRestart->onStart->onResume,又重新恢複。

情形三、基本情形同二一樣,不過此時a被b部分遮蓋(比如給b添加個對話框主題 android:theme="@android:style/Theme.Dialog")

a經曆的過程是:onCreate->onStart->onResume->onPause->onResume

是以當Activity被部分遮擋時,Activity進入onPause,并沒有進入onStop,從Activity2傳回後,執行了onResume

情形四、 打開程式,啟動a,點選a,啟動AlertDialog,按傳回鍵從AlertDialog傳回。

a經曆的過程是:onCreate->onStart->onResume

當啟動和退出Dialog時,Activity的狀态始終未變,可見,Dialog實際上屬于Acitivity内部的界面,不會影響Acitivty的生命周期。