Activity總結

Activity是什麼?

相信大家都知道Android中的4大組件(Activity活動,Service服務,ContentProvider內容提供者,BroadcastReceiver廣播接收器),Activity是我們使用最多的也是最基本的組件,Activity提供窗口和用戶進行交互.

Android中的activity全都歸屬於task管理(task是一個具有棧結構的容器),task是多個activity的集合,android默認情況會爲每個App維持一個task來存放app的所有activity(當然這只是默認情況),task的默認name爲該apppackagename(包名)

當然我們也可以在AndroidMainfest.xml中申明activity taskAffinity 屬性來自定義task,但是不建議使用,因爲如果其他app也申明瞭同樣的task,那個app可能啓動到你的activity,這樣會帶來各種安全問題(比如拿到你的Intent).

Activity的內部調用

上面我們介紹過了,系統是通過task(棧)的方式來管理activity的,當一個新的activity開始的時候,該activity會被放置在堆棧(back stack)的頂部,成爲正在運行的活動,之前的activity始終保持低於它在堆棧,而不會出現在前臺.

官方activity_lifecycle:


activity

當我們打開一個新的activity實例的時候,系統會以此調用

onCreate() -> onStart() -> onResume() 然後開始running

activity在running的時候如果被覆蓋(打開新的activity,或者被鎖屏,但是它依然在前臺運行,lost focus but is still visible),系統就會調用onPause();

onpause()方法中,我們通常會提交未保存的更改到持久化數據,停止動畫和其他東西.但是我們要知道現在這個activity還是完全活着(它保存所有的狀態和成員信息,並且保存到窗口管理器的連接)

  • 1.啓動Activity:系統會先調用onCreate方法,然後調用onStart方法,最後調用onResumeActivity進入運行狀態。
  • 2.當前Activity被其他Activity覆蓋其上或被鎖屏:系統會調用onPause方法,暫停當前Activity的執行。
  • 3.當前Activity由被覆蓋狀態回到前臺或解鎖屏:系統會調用onResume方法,再次進入運行狀態。
  • 4.當前Activity轉到新的Activity界面或按Home鍵回到主屏,自身退居後臺:系統會先調用onPause方法,然後調用onStop方法,進入停滯狀態。
  • 5.用戶後退回到此Activity:系統會先調用onRestart方法,然後調用onStart方法,最後調用onResume方法,再次進入運行狀態。
  • 6.當前Activity處於被覆蓋狀態或者後臺不可見狀態,即第2步和第4步,系統內存不足,殺死當前Activity,而後用戶退回當前Activity:再次調用onCreate方法、onStart方法、onResume方法,進入運行狀態。
  • 7.用戶退出當前Activity:系統先調用onPause方法,然後調用onStop方法,最後調用onDestory方法,結束當前Activity

onSaveInstanceState:(1)在Activity被覆蓋或退居後臺之後,系統資源不足將其殺死,此方法會被調用;(2)在用戶改變屏幕方向時,此方法會被調用;(3)在當前Activity跳轉到其他Activity或者按Home鍵回到主屏,自身退居後臺時,此方法會被調用。第一種情況我們無法保證什麼時候發生,系統根據資源緊張程度去調度;第二種是屏幕翻轉方向時,系統先銷燬當前的Activity,然後再重建一個新的,調用此方法時,我們可以保存一些臨時數據;第三種情況系統調用此方法是爲了保存當前窗口各個View組件的狀態。onSaveInstanceState的調用順序是在onPause之前。

onRestoreInstanceState:(1)在Activity被覆蓋或退居後臺之後,系統資源不足將其殺死,然後用戶又回到了此Activity,此方法會被調用;(2)在用戶改變屏幕方向時,重建的過程中,此方法會被調用。我們可以重寫此方法,以便可以恢復一些臨時數據。onRestoreInstanceState的調用順序是在onStart之後。

activity被回收的狀態和信息保存和恢復過程

public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        if(savedInstanceState!=null){ //判斷是否有以前的保存狀態信息
             savedInstanceState.get("Key"); 
             }
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
   @Override
protected void onSaveInstanceState(Bundle outState) {
    // TODO Auto-generated method stub
     //可能被回收內存前保存狀態和信息,
       Bundle data = new Bundle(); 
       data.putString("key", "last words before be kill");
       outState.putAll(data);
    super.onSaveInstanceState(outState);
}
   @Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    // TODO Auto-generated method stub
       if(savedInstanceState!=null){ //判斷是否有以前的保存狀態信息
             savedInstanceState.get("Key"); 
             }
    super.onRestoreInstanceState(savedInstanceState);
}
}

onSaveInstanceState()方法,在activity被回收之前調用,用來保存自己的狀態信息,以便回收後重建時恢復數據(在onCreate()onRestoreInstanceState()中恢復).旋轉屏幕重建activity會調用該方法,但其他情況在onRause()onStop()狀態的activity不一定會調用,
下面是官方文檔說明:

  One example of when onPause and onStop is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause is called and not onSaveInstanceState is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.

也就是說,系統靈活的來決定會不會調用該方法,但是如果要調用就一定發生在onStop方法之前,但不保證發生在onPase的前面還是後面.

onRestoreInstanceState()該方法在onstartonPostCreate之間調用,當然我們也可以在onCreat中恢復之前我們在onSaveInstanceState()中保存下來的數據,但是我們有時候需要在初始化佈局完成之後再恢復數據,這是就可以在onRestoreInstanceState()中恢復數據.
onPostCreate():一般我們都沒有實現這個方法,它的作用是在代碼開始運行之前,調用系統做最後的初始化工作.

關於啓動模式

啓動模式是什麼?

簡單點說就是:定義activity實例與task的關聯方式

爲什麼我們要定義啓動模式呢?

爲了實現默認啓動(standard)模式之外的需求:

  • 讓某個activity啓動一個新的task(而不是被放入當前task)
  • 讓activity啓動時只調用已有的某個實例(而不是在back stack(之前我們有提到過喲) 頂創建一個新的實例)
  • 當用戶離開task時只想保留根activity,而back stack中的其他activity都要清空.

怎樣定義啓動模式

定義啓動模式的方法有2種:
  • 使用manifest文件定義
  • 使用Intent標誌定義

使用manifest文件定義啓動模式:
在 manifest 文件中activity聲明時,利用 activity 元素的 launchMode 屬性來設定 activity 與 task 的關係。

<activity
            ......
            android:launchMode="standard"
             >
           .......
</activity>

注意: 你用 launchMode 屬性爲 activity 設置的模式可以被啓動 activity 的 intent 標誌所覆蓋,代碼的優先級最高。

現在我們知道了怎麼定義啓動模式了,但是有哪些啓動模式呢?

  • standard (默認模式)
    當通過這種模式啓動activity時,Android總會爲目標 Activity創建一個新的實例(之前有過也會重新創建),並將該Activity添加到當前Task棧中。這種方式不會啓動新的Task,只是將新的 Activity添加到原有的Task中。

  • singleTop
    該模式和standard模式基本一致,但有一點不同:當將要被啓動的Activity已經位於Task棧頂時,系統不會重新創建目標Activity實例,而是直接複用Task棧頂的Activity。

  • singleTask
    Activity在同一個Task內只有一個實例。
    如果將要啓動的Activity不存在,那麼系統將會創建該實例,並將其加入Task棧頂; 

  如果將要啓動的Activity已存在,且存在棧頂,直接複用Task棧頂的Activity。 

  如果Activity存在但是沒有位於棧頂,那麼此時系統會把位於該Activity上面的所有其他Activity全部移出Task,從而使得該目標Activity位於棧頂。


  • singleInstance
     無論從哪個Task中啓動目標Activity,只會創建一個目標Activity實例且會用一個全新的Task棧來裝載該Activity實例(全局單例).

  如果將要啓動的Activity不存在,那麼系統將會先創建一個全新的Task,再創建目標Activity實例並將該Activity實例放入此全新的Task中。

  如果將要啓動的Activity已存在,那麼無論它位於哪個應用程序,哪個Task中;系統都會把該Activity所在的Task轉到前臺,從而使該Activity顯示出來。

和"singleTask"類似,唯一不同的是系統不會在這個activity的實例所在的task中啓動任何其他activity。

  這個activity的實例永遠是這個task中的唯一一個成員,這個activity啓動的任何其他activity都將在另外的task中打開。



使用Intent標識定義啓動模式:

  • FLAG_ACTIVITY_NEW_TASK
    和之前討論過的"singleTask"相同,在新的task中啓動activity,如果一個你需要的activity的task已經存在,則將它推向前臺,恢復其上一個狀態,它通過onNewIntent()收到這個新的intent。
  • FLAG_ACTIVITY_SINGLE_TOP
    和"singleTop"行爲相同,如果被啓動的activity是當前頂部的activity,則已經存在的實例收到 onNewIntent()
    ,而不是新建實例。

  • FLAG_ACTIVITY_CLEAR_TOP
    如果被啓動的activity已經在當前task運行,不創建它的新實例,而是銷燬在它之上的其他所有activities,然後通過 onNewIntent()
    傳遞一個新的intent給這個恢復了的activity。
      這個行爲在 launchMode 中沒有對應的屬性值。
      注意,如果activity的啓動模式是"standard",它自己也將被移除,然後一個新的實例將被啓動。
      這是因爲當啓動模式是"standard"時,爲了接收新的intent必須創建新的實例。


處理affinities

Affinity指示了activity更傾向於屬於哪個task。
  默認情況下,同一個應用的activities傾向於在同一個task中。你可以通過<activity>標籤中的 taskAffinity 來修改這種行爲。
  詳細內容請查看:API Guides: Tasks and Back Stack
  http://developer.android.com/guide/components/tasks-and-back-stack.html


開啓一個task

你可以通過給activity一個intent filter(action是"android.intent.action.MAIN",category是"android.intent.category.LAUNCHER"),讓這個activity是一個task的進入點。

  如下:

<activity ... >
    <intent-filter ... >
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
    ...
</activity>

一個這樣的intent filter會使得這個activity的icon和label顯示在程序啓動處,提供了一種方法,使得用戶可以啓動這個activity,當它啓動後,用戶也可以通過它來返回到這個task。
  第二個能力是很重要的:用戶必須能夠離開一個task,然後通過activity launcher返回到它。
  因爲這個原因,兩個讓activity永遠實例化一個task的啓動模式:"singleTask" 和"singleInstance",應該僅在activity有一個 ACTION_MAIN 和CATEGORY_LAUNCHER filter的時候用它們。

至此,相信大家對Activity有了更深的瞭解了吧~~~
發佈了44 篇原創文章 · 獲贊 87 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章