Activity啟動模式的理解

前言

我們知道,Activity的維護是在任務棧來管理的,而棧的數據是先進后出,默認情況下,當我們啟動一個Activity的時候,就是把這個Activity放到任務棧中,相當于進棧,而關閉一個Activity的時候,相當于出棧。

主要內容:

  1. 為什么要有啟動模式
  2. 四種啟動模式的區別
  3. 啟動模式與生命周期
  4. 啟動模式的應用

1. 為什么要有啟動模式

因為在默認情況下,當我們多次啟動同一個Activity的時候,Android系統會創建多個同樣的實例放到棧中,這樣是不合理的,所以Android系統提供了4種啟動方式給我們使用。分別是:standard(標準模式),singleTop(棧頂復用模式),singleTask(棧內復用模式),singleInstance(單實例模式)

2. 四種啟動模式區別

  • standard模式 (標準模式)
    在沒有給Activity指定啟動模式時候的系統默認模式,每次啟動一個Activity都會重新創建一個Activity新的實例,放入任務棧的棧頂,被創建的Activity都會調用onCreate(),onStart(),onResume()三個方法。一個任務棧可以有多個實例,而每個實例也可以屬于不同的任務棧,在默認模式下,哪個Activity啟動了另一個Activity,則這個Activity就會運行在啟動它的Activity的任務棧中(當使用Application啟動Activity的時候,是會報錯的,因為Application類型的context沒有任務棧,這是需要加入一個FLAG_ACTIVITY_NEW_TASK標記,創建一個任務棧,這時啟動的Activity實際是以singleTask模式啟動的)。

  • signleTop(棧頂復用模式)
    此模式其實是解決了一開始說的問題,就是多次啟動同一個Activity的時候,會創建多個實例的問題。在該模式下,如果啟動的Activity已經位于任務棧的棧頂,那么此Activity不會被重新創建,并且該Activity的onNewIntent方法回被調用,通過該方法的參數我們得到當前請求的信息,而onCreate(),onStart()不會被回調,因為Activity并沒有改變(例如瀏覽器的書簽Activity就可以應用該模式)

  • singleTask(棧內復用模式)
    在該模式下,啟動一個Activity會先檢查棧內是否有該Activity的實例,有該實例則不會重復創建,并且把在該實例前面的Activity全部出棧,也同樣會調用onNewIntent方法,如果不存在則會新創建一個任務棧,并把該Activity放入任務棧中。

  • singleInstance(單實例模式)
    在該模式下Activity會單獨占用一個任務棧,并且,他有棧內復用性,由于任務棧有棧內復用性,后續請求不會創建一個新的Activity實例,除非該任務棧被系統銷毀。(該模式可以應用于我們手機接電話的界面,不管有多少個電話打進來,只能有一個接電話的界面,如果不是使用單實例模式,如果有多個電話打進來,手機就可能由于多個Activity占用內存太多而卡死了)。

3. 啟動模式&生命周期

這里簡單說下不同啟動模式下,Activity的生命周期的情況:
首先,我們假設有 3 個Activity A,B,C

  • standard模式:
    A->B->C
//啟動A
D/activityA(19864): onCreate
D/activityA(19864): onStart
D/activityA(19864): onResume
//啟動B
D/activityA(19864): onPause
D/activityB(19864): onCreate
D/activityB(19864): onStart
D/activityB(19864): onResume
D/activityA(19864): onStop
//啟動C
D/activityB(19864): onPause
D/activityC(19864): onCreate
D/activityC(19864): onStart
D/activityC(19864): onResume
D/activityB(19864): onStop

然后按返回鍵:

D/activityC(19864): onPause
D/activityB(19864): onRestart
D/activityB(19864): onStart
D/activityB(19864): onResume
D/activityC(19864): onStop
D/activityC(19864): onDestory

所以如果未調用onDestory重新啟動的話,不會調用onCreate,而是會調用onRestart

然后我們看看 A->B->A

D/activityA(19864): onCreate
D/activityA(19864): onStart
D/activityA(19864): onResume

D/activityA(19864): onPause
D/activityB(19864): onCreate
D/activityB(19864): onStart
D/activityB(19864): onResume
D/activityA(19864): onStop

D/activityB(19864): onPause
D/activityA(19864): onCreate
D/activityA(19864): onStart
D/activityA(19864): onResume
D/activityB(19864): onStop
  • singleTop
    修改A的啟動模式為singleTop
    ->A->A
D/activityA(27075): onCreate
D/activityA(27075): onStart
D/activityA(27075): onResume


D/activityA(27075): onPause
D/activityA(27075): onNewIntent
D/activityA(27075): onResume

->A->B->A

D/activityA(27075): onCreate
D/activityA(27075): onStart
D/activityA(27075): onResume


D/activityA(27075): onPause
D/activityB(27075): onCreate
D/activityB(27075): onStart
D/activityB(27075): onResume
D/activityA(27075): onStop

D/activityB(27075): onPause
D/activityA(27075): onCreate
D/activityA(27075): onStart
D/activityA(27075): onResume
D/activityB(27075): onStop

當A不是棧頂時,啟動A,又重新創建了A,而且觀察以上輸出,兩個Activity切換時,首先當前Activity先onPause,然后被啟動的Activity,依次onCreate, onStart, onResume顯示出來之后,之前的Activity才會onStop。

  • signleTask
    修改A的啟動方式為singleTask,
    ->A->A
D/activityA( 2744): onCreate
D/activityA( 2744): onStart
D/activityA( 2744): onResume



D/activityA( 2744): onPause
D/activityA( 2744): onNewIntent
D/activityA( 2744): onResume

當A不存在時,創建A,當A存在且在棧頂時,先onPause,然后onNewIntent,之后onResume。

->A->B->A

D/activityA( 2744): onCreate
D/activityA( 2744): onStart
D/activityA( 2744): onResume

D/activityA( 2744): onPause
D/activityB( 2744): onCreate
D/activityB( 2744): onStart
D/activityB( 2744): onResume
D/activityA( 2744): onStop

D/activityB( 2744): onPause
D/activityA( 2744): onNewIntent
D/activityA( 2744): onRestart
D/activityA( 2744): onStart
D/activityA( 2744): onResume
D/activityB( 2744): onStop
D/activityB( 2744): onDestory

可以看到第二次啟動A后,A調用了onNewIntent,onRestart,onStart,onResume,關鍵是之后調了B的onStop, onDestory,在之前的兩種模式下只是另B,調用了onStop,所以推斷,singleTask時,是之前的A通過onNewIntent重新進入onResume,然后將B移除出了棧。

  • singleInstance
    修改A的啟動方式為SingleInstance
    ->A->A
D/activityA(10578): onCreate
D/activityA(10578): onStart
D/activityA(10578): onResume


D/activityA(10578): onPause
D/activityA(10578): onNewIntent
D/activityA(10578): onResume

與singleTask表現一致

->A->B->A

D/activityA(10578): onCreate
D/activityA(10578): onStart
D/activityA(10578): onResume

D/activityA(10578): onPause
D/activityB(10578): onCreate
D/activityB(10578): onStart
D/activityB(10578): onResume
D/activityA(10578): onStop

D/activityB(10578): onPause
D/activityA(10578): onNewIntent
D/activityA(10578): onRestart
D/activityA(10578): onStart
D/activityA(10578): onResume
D/activityB(10578): onStop

在singleInstance模式下,復用了原來的A,對B只是onStop,并沒有發生出棧銷毀。

總結以上:

當復用一個已經存在的Activity時,通常是從它的onNewIntent或onRestart開始調起,

如果一個Activity要出棧,必然會調到onDestory

在兩個Activity切換的過程中,是當前的Activity先onPause,然后讓新的Activity創建或者restart,直到onResume,前一個Activity才會走onStop以及onDestory

4. 啟動模式的應用

啟動模式是Android最基礎的,也是很重要的知識點,那么他在我們日常使用的APP種,哪些地方使用到他們了呢?

  • standard模式: 一般界面沒有特殊要求,直接使用標準模式
  • singleTop模式:瀏覽器標簽欄使用該模式
  • singleTask模式:我們平常看到的HOME界面,比如你在登錄界面登錄成功后,需要回到HOME界面
  • singleInstance模式:電話來電界面使用該模式
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容