1. 程式人生 > >深入剖析Android四大組件(一)——Activity生命周期具體解釋

深入剖析Android四大組件(一)——Activity生命周期具體解釋

err ace troy 觀察 cin andro idp 方便 存儲

1.管理Activity的生命周期


不管是正在執行的Activity還是沒有執行的Activity,它們都接受Android的框架管理,這使得Activity處於不同的生命周期。


Activity的3種狀態

通過回調方法來管理Activity的生命周期對於開發一個健壯而且靈活的應用程序是很關鍵的。

Activity的生命周期直接影響到它與其它Activity,任務以及棧的關系。

Activity存在3種狀態。各自是resumed,pausedstopped

?resumed:指Activity在屏幕前臺而且擁實用戶焦點的狀態。這個狀態有時也稱為“正在執行”

paused:指還有一個

Activity在屏幕前臺而且擁實用戶焦點的狀態,但這個Activity仍然可見。即還有一個Activity在前一個Activity之上。而前一個Activity又是可見的而且部分透明或者沒有覆蓋整個屏幕。一個處於paused狀態的Activity是全然存活的(Activity對象村中被保留,它維護全部狀態和成員信息,並依舊依附窗體管理器),可是在內存極低時將被系統殺掉。

stopped:指前一個Activity被還有一個Activity全然遮蔽(前一個Activity當前在後臺中)。

一個處於stopped狀態的Activity仍然是存活的(這個Activity對象在內存中被保留,它維護全部狀態和成員信息,但沒有依附窗體管理器)。然而。它卻不再顯示給用戶,而且在內存極低時會被系統殺掉。

假設一個Activity處於pausedstopped狀態,那麽系統會從內存中丟掉它。這能夠通過調用它的finish()方法來實現,或者簡單一點,通過殺掉它的進程來實現。

Activity又一次打開(在它結束或者被殺掉之後)時,它就必須被又一次創建。

②實現Activity的生命周期回調

Activity發生狀態轉變時,它會通過回調方法來得到通知,我們能夠重寫全部這些回調方法完畢適當的工作。

Activity狀態發生改變時,Activity的框架包括每個主要的生命周期方法,例如以下列代碼所看到的:


@Override

public void onCreate(Bundle savedInstanceState){

//指示這個Activity正在被創建

super.onCreate(saveInstanceState);

//完畢一些任務

}


@Override

protected void onStart(){

//這個Activity正在變為可見

super.onStart();

//完畢一些任務

}


@Override

protected vodi onResume(){

//這個Activity已經變為可見

//如今是resumed狀態

super.onResume();

//完畢一些任務

}


@Override

oritected void onPause(){

//還有一個Activity獲得焦點並且當前的Activity失去焦點

//也就是當前Activity被還有一個Activity部分或者所有覆蓋

//當前Activity失去焦點的時候調用

//這個Activity如今處於paused狀態

super.onPause();

//完畢一些任務

}


@Override

protected void onStop(){

//這個Activity不再可見的時候調用

//當前Activity處於stopped狀態

super.onStop();

//完畢一些任務

}


@Override

protected void onDestory(){

//這個Activity已經被銷毀

super.onDestory();

//完畢一些任務

}

建議:通常,在實現這些生命周期方法時,必須先調用超類的實現(比方調用super.XXX)。綜上所述,以上這些方法定義了Activity的整個生命周期。通過實現這些方法,我們就能監視Activity生命周期中的3個嵌套循環,詳細例如以下所看到的。

?Activity的整個生命周期發生在調用onCreate()和調用onDestory()之間。

onCreate()中,Activity應該設置“全局”狀態(比方定義布局),而且在onDestory()中釋放其余資源。比如,假設Activity有一個後臺執行的線程從網絡上下載數據,那麽它應該在onCreate()中創建這個線程,而且在onDestory()停止該線程。

Activity的可見生命周期發生在調用onStart()和調用onStop()之間。在這個過程中,用戶能夠看到這個Activityd在屏幕中而且能夠與之交互。比如。當一個新Activity啟動而且前一個Activity不再可見的時候,onStop()就被調用了。在這兩個方法之間,能夠維護須要顯示給用戶的Activity資源。比如,能夠在onStart()方法中註冊一個廣播接收器去監視影響UI的變化,當用戶看不到顯示的東西時。則在onStop()註銷它。在Activity的整個生命周期中。當Activity在可見和隱藏之間切換時,系統就會多次調用onStart()onStop()方法。

Activity的前臺生命周期發生在調用onResume和調用onPause()之間。須要說明的是。在這期間,Activity在屏幕中全部其它Activity的前面而且擁實用戶焦點。

普通情況下。Activity能夠被頻繁轉換。

比如。當設備休眠或者顯示一個對話框時,onPause()就會被調用。

對於以上知識,為了方便讀者理解並理順它們之間的內在關系,我們用一張圖來直觀地描寫敘述。例如以下圖:


技術分享

上圖為Activity生命周期的演化過程


順便也列出一張表。描寫敘述了在Activity的整個生命周期裏定位的每個回調方法以及其細節,以及回調方法完畢後系統能否夠停止這個Activity等。


方法 描寫敘述 調用後能否夠被殺掉 下一步操作
onCreate() 當Activity第一次被創建時調用。此處能夠做全部的一般靜態設置,比方創建視圖,綁定列表數據等。


假設狀態被捕捉,而且此狀態存在的話。這種方法傳遞一個包括這個Activity的前狀態的Bundle對象。

onStart()
onRestart() Activity被停止後。再次啟動之前調用。

onStart()
onStart() 在Activity對用戶可見之前被調用。


假設這個Activity來到前臺,那麽下一步操作是調用OnResume()。
假設被隱藏,則下一步操作是調用onStop()。

onResume()或者onStop()
onResume() 在Activity開始與用戶交互之前被調用。在這裏,該Activity位於Activity棧頂。開始與用戶交互。
須要註意的是,此時當前Activity處於resumed狀態。這個狀態下Activity是可見的。
onPause()
onPause() 當系統正在恢復還有一個Activity的時候被調用。這種方法通經常使用於提交未保存的數據,停止動畫以及可能 消耗CPU的事情等。這些應該高效地完畢,由於下一個Activity在這種方法沒有返回之前不會被執行。假設Activity回到前臺,則下一步操作為調用onResume()。假設Activity變得不可見。則調用onStop(). onResume()或者onStop()
onStop() 當Activity對用戶不再可見的時候調用。

這會發生,是由於它正在被銷毀或者還有一個Activity(能夠是已經存在的或者新的)被執行而且覆蓋了它。
假設Activity恢復與用戶交互。則下一步操作是調用onRestart(),假設這個Activity消失。則調用onDestory()。

onRestart()或者onDestory()
onDestory() 該Activity被銷毀之前調用。這個Activity收到的終於調用。它能夠是由於Activity正在結束(調用finish()),或者是由於心痛為保護空間而面臨銷毀這個Activity的實例而調用。能夠通過isFinishing()方法區分這兩種情況。



2.保存和協調Activity



在Activity切換狀態的時候。可能須要保存一些中間狀態。比方控件的選擇狀態等。以便當它又一次被顯示出來時仍能夠恢復到之前推出的狀態。



①保存Activity狀態


當一個Activity被暫停或者停止的時候。它的狀態被保留。由於當它被暫停或者停止的時候,Activity對象仍然駐留在內存中——全部有關它的成員變量和當前狀態的信息仍然存在。因此,全部用戶導致的Activity的變化就被保存在內存中。而當這個Activity返回到前臺時(當它被恢復時)。這些變化仍然在內存中。

然而。當系統為恢復內存而銷毀一個Activity時,這個Activity對象也就被銷毀了。此時系統就不能簡單地恢復它並持有它的完整狀態。

取而代之的是。假設用戶再次導航到這裏,系統就必須又一次創建這個Activity對象,可是用戶不知道系統已經銷毀了該Activity而如今又又一次創建了它。因此,用戶可能覺得這個Activity就是之前的那個Activity。在這樣的情況下,我們能夠通過實現一個附加的同意保存我們Activity狀態信息的回調方法,而將關於Activity狀態的重要信息保留下來,然後當系統又一次創建這個Activity的時候,再去又一次存儲它。



保存Activity當前狀態信心的回調方法是onSaveInstanceState()。系統在Activity被銷毀之前調用此方法,並再傳一個Bundle對象。這個Bundle對象能夠存儲Activity狀態(以名稱--值對的形式)信息,能夠使用像putString()之類的方法。

那麽,假設系統停止掉Activity進程。而且用戶又又一次啟動該Activity,那麽系統進程會將這個Bundle對象傳遞給onCreate(),這樣就能夠恢復onSaveInstanceState()中保存的Activity狀態了。假設沒有為恢復的狀態信息,那麽傳給onCreate()的Bundle對象則是null。



註意:由於保存應用程序狀態不是必要的行為。所以不能確保onSaveInstanceState()在Activity被銷毀之前調用(比如當用戶由於明白關閉而使用BACK鍵離開該Activity時)。假設這種方法被調用,那麽它將總是在onStop()並有可能在onPause()之前調用。

盡管如此,但即使你沒有實現onSaveInstanceState()方法,也還是有一些Activity的狀態通過Activity類默認實現的onSaveInstanceState()方法恢復。特別是,默認實現會為布局中的每個視圖調用onSaveInstanceState(),同意每個視圖提供它們自己要保存的信息。差點兒每個Android框架中的部件都會適當地實現這種方法。這樣一來,當Activity被又一次創建的時候,不論什麽一個對於UI可見的變化都被自己主動保存和恢復。比如,EditText空間保存用戶輸入的全部文本,CheckBox空間保存它是否被選擇。而我們須要做的僅僅是為全部想要保存狀態的空間提供一個唯一的ID(借助android:id屬性)。

雖然onSaveInstanceState()的默認實現會保存這個Activity UI的實用信息,可是我們可能仍然須要重寫它以便保存額外的信息。比如。我們可能須要保存在整個Activity生命周期中變化的成員變量的值。因為默認實現的onSaveInstanceState()幫助保存UI的狀態,所以假設重寫這種方法是為了保存額外的信息。那麽就應該在做不論什麽工作之 前先調用超類的onSaveInstanceState()方法。



註意:由於我們不能保證onSaveInstanceState()會被調用。所以使用它僅僅能夠記錄Activity的瞬間狀態,而不能用來保存持久數據。相反,當用戶離開這個Activity時,應該用onPause()保存持久數據(比如那些應該保存到數據庫中的數據)。

下圖直觀的展現了Android是怎樣保存這些狀態的。

技術分享



技術分享

上圖為Android保存這些狀態的流程示意圖

假設須要恢復保存的狀態,應該都知道Activity的生命周期中有一個onCreate()方法中傳遞了一個Bundle對象。詳細恢復的代碼例如以下所看到的:

@Override public void onCreate(Bundle saveInstanceState){ super.onCreate(saveInstanceState); if(saveInstanceState!=null){
//獲取你保存的狀態信息 } }

這樣一來,當界面被創建的時候,Activity仍然能找到用戶最後操作的數據。

須要註意的是,憂郁我們不能保證是否存在保存的狀態。因此須要一個推斷來鑒別if(saveInstanceState!=null)。

②協調Activity



當一個Activity啟動還有一個Activity的時候,它們都會經歷各自的生命周期的改變。第一個Activity被暫停或停止(假設它仍然可見,就不會被停止)時。還有一個Activity被創建。而這些Activity共享的數據被保存到磁盤或別的地方。

生命周期回調的順序要非常好地定義,尤其是當兩個Activity在同一個過程中而且一個正在啟動還有一個的時候。

以下給出了Activity A啟動Activity B的順序。



第一,Activity A運行onPause()方法。



第二,Activity B順序運行onCreate(),onStart(),onResume()方法(Activity如今獲得用戶焦點)。



第三,假設Activity A在屏幕中不再可見,則它的onStop()方法就會被運行。

這個生命周期回調的序列同意我們管理從一個Activity到還有一個Activity轉變的信息。

比如。假如必需要寫數據庫,則當第一個Activity停止的時候,那麽緊跟著的Activity就能夠讀取那個停止了的Activity。這種話,我們就應該在onPause()中而不是在onStop()中寫數據庫。



3.用實例說話


這個實例很easy,它包括兩個Activity,它們都實現了全部的生命周期回調接口,而且還實現了相關的Activity狀態保存與狀態恢復的回調方法。此外。我們還能夠從一個Activity導航到還有一個Activity上。詳細的操作過程例如以下所看到的。


①創建一個名為ActivityLife的project。包名為helloworld.liyuanjing.example.com.activitylife。

創建完畢後,我們就在原有的基礎上加入一個新類SecondActivity,它繼承自Activity類。

此時Androidproject中就擁有兩個Java代碼文件,它們各自是MainActivity.java和SecondActivity.java。如今。這兩個代碼都實現生命周期的全部方法。並在各個方法中加入日誌。加入日誌的方法例如以下:


Log.e(TAG, message);


②將新增的類SecondActivity聲明到AndroidManifest.xml文件裏去,這一步很重要。假設沒有這一步,就無法啟動SecondActivity。聲明代碼例如以下:


<activity android:name=".SecondActivity"></activity>


在AndroidManifest.xml中聲明一個Activity有相當多的講究,這裏僅僅做簡單配置上去,從而使得我們的Activity能夠正常啟動。如需深入清單文件能夠到http://blog.csdn.net/column/details/androidmanifest.html該專欄下一探到底。


再者,為了實現從MainActivity上啟動SecondActivity,我們須要在默認的布局文件(activity_main)中加入一個button。

而且實現它的單擊事件。在該事件中。啟動SecondActivity。改動後的布局代碼例如以下:


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/hello_world" />

<Button
android:id="@+id/mybut"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="To SecondActivity"/>
</LinearLayout>


改動後的MainActivity的代碼例如以下:


public class MainActivity extends Activity {
    public static final String TAG="MainActivity";
    private Button mybut=null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e(TAG, "MainActivity::onCreate()");
        this.mybut=(Button)findViewById(R.id.mybut);
        this.mybut.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(MainActivity.this,SecondActivity.class));
            }
        });
    }
    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "MainActivity::onStart()");
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "MainActivity::onResume()");
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "MainActivity::onPause()");
    }
    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "MainActivity::onStop()");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "MainActivity::onDestroy()");
    }
    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG, "MainActivity::onSaveInstanceState()");
    }
}


SecondActivity的代碼例如以下:


public class SecondActivity extends Activity {
    public static final String TAG="SecondActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e(TAG, "SecondActivity::onCreate()");
    }
    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "SecondActivity::onResume()");
    }
    @Override
    protected void onStart() {
        super.onStart();
        Log.e(TAG, "SecondActivity::onStart()");
    }
    @Override
    protected void onPause() {
        super.onPause();
        Log.e(TAG, "SecondActivity::onPause()");
    }
    @Override
    protected void onStop() {
        super.onStop();
        Log.e(TAG, "SecondActivity::onStop()");
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "SecondActivity::onDestroy()");
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG, "SecondActivity::onSaveInstanceState()");
    }
}


③編譯執行project,註意觀察日誌。等到應用程序展現出來的時候,就能夠觀察到例如以下圖所看到的的日誌信息:


技術分享


出現這種界面就說明,一個Activity從啟動到展示完畢經歷了從onCreate()到onStart()。在再到onResume的3個階段。


④單擊“導航”button,也就是布局文件那個button,啟動SecondActivity,看看有什麽樣的日誌輸出,例如以下圖:


技術分享


此時。SecondActivity就呈現出來了。而原來的MainActivity則被SecondActivity覆蓋掉而不再擁實用戶焦點。因此,可得出以下的3個結論。


ⅠMainActivity的onPause()方法被調用。


ⅡSecondActivity將會經歷與MainActivity一樣的顯示過程。


Ⅲ當完畢SecondActivity的展現後,MainActivity保存的回調接口(onSaveInstanceState())就被調用。接著還會調用MainActivity的onStop()方法。


⑤按BACK鍵返回到原來的Activity,看看會發生什麽?例如以下圖:


技術分享


從上圖可知。發生了以下4件事情。


ⅠSecondActivity的onPause方法被調用。指示它即將被暫停。


Ⅱ因為MainActivity是以前被創建的Activity,因此這裏僅僅調用了它的onStart()以及onResume()方法來完畢Activity的又一次展現。


ⅢSecondActivity完畢了生命周期而被銷毀。

在這個過程中。它經歷了停止和銷毀兩個生命周期。這也就意味著當須要它又一次顯示的時候,僅僅能從又一次創建開始了。



Ⅳ假設此次再次按下BACK鍵,則MainActivity也將被銷毀。相同,它的onStop()以及onDestory()也會被依次調用。

深入剖析Android四大組件(一)——Activity生命周期具體解釋