天天看點

Activity啟動模式&Task棧

在AMS中,ActivityRecord對應一個Activity,TaskRecord對應一個Task,每個TaskRecord中儲存了若幹ActivityRecord,TaskRecord由taskId辨別,通過getTaskId()可以擷取Activity所屬的Task。ActivityStack中的TaskRecord清單儲存了AMS中所有的Task資訊,ActivityStack、Task、Activity三者的對應關系如下:

Activity啟動模式&Task棧

Activity Task ActivityStack對應關系

其中ActivityStack處于ASM所屬程序,ActivityThread在APP所屬程序。可以看到ActivityStack中儲存了TaskRecord清單,TaskRecord中儲存了Activityrecord清單。在建立或者回退Activity的時候,就是對ActivityStack中TaskRecord的ActivityRecord進行出棧和入棧操作。

Task圖示法:

Activity啟動模式&Task棧

上圖是本文Task的圖示法,Task标記為

“Task_task名(TaskAffinity)”,Task的TaskAffinity屬性是其根Activity的TaskAffinity值

;Task中的Activity标記為

"應用名_Activity名(TaskAffinity)”

,Activity的

TaskAffinity

通過AndroidManifest.xml中配置。中間的黑線表示Home,黑線下方是點home鍵退到背景的Task。

taskAffinity:

AndroidManifest.xml中可以給應用配置taskAffinity屬性,不設定預設會使用應用的包名作為taskAffinity,taskAffinity隻有在FLAG_ACTIVITY_NEW_TASK、singleTask、singleInstance的時候有效。桌面打開應用,由于Launcher使用了FLAG_ACTIVITY_NEW_TASK來啟動應用,是以會根據主界面設定的taskAffinity或者預設的taskAffinity來查找或建立新的Task,具有相同taskAffinity的Task推到前台。

也就是說,應用沒有啟動是點選桌面應用圖示會啟動一個新的Task,如果應用已經啟動,退到home背景後,再次點選圖示,會将home背景的task原封不動重新推到前台,如果rootActivity是singleTask的話,就會将rootActivity上面的Activity對象出棧,然後再将Task推到前台。

Activity啟動模式

1、standard
Activity啟動模式&Task棧

入棧

A_b、B_c都是standard模式,A_a啟動了A_b,A_b啟動了B_c,B_c又啟動了A_b,可以得出如下結論:被啟動的Activity如果是standard模式(

即使啟動者和被啟動者位于不同的APP

),那麼被啟動的Activity會儲存在啟動者所屬的Task中(不論是否設定了TaskAffinity屬性),且不論該Task中是否存在被啟動執行個體,都會建立一個新的執行個體壓入棧中。在按back鍵時也是一個一個的出棧。

2、singleTop
Activity啟動模式&Task棧

應用A啟動應用B的B_b Activity,B_b是singleTop啟動模式,那麼再次啟動B_b時,如果棧頂元素是B_b,就不再建立B_b執行個體。不論啟動者和被啟動者是否屬于同一個應用,被啟動的Activity和啟動的Activity都會在同一個Task中。

singleTop屬性和allowTaskReparenting混合使用會出現什麼場景? allowTaskReparenting

假設所有的Activity啟動模式都是standard的,這裡沒有加上TaskAffinity,表明該屬性不影響Task的歸屬。有如下運作流程:

Activity啟動模式&Task棧

這裡A_b設定了

=true;

1)、首先啟動了應用A的主界面A_a,然後A_a啟動了A_b,A_a和A_b都在Task_a中,這時按下home鍵

2)、啟動應用B的主界面B_c,B_c啟動了B_d,B_d又啟動了A_b,由于A_b是standard的,是以B_c、B_d和A_b在同一個Task_b中,這時再按下home鍵

3)、再次點選桌面的A應用,系統會把Task清單中Task_a推到前台,由于A_b設定了

屬性,是以Task_b中的A_b執行個體也被轉移到了Task_a中。這就是

屬性的作用,該屬性在task從背景切換到前台的時候起作用。

如果設定A_b的啟動模式為singleTop,上面的執行流程依然正确,但是卻發現Task_a的棧頂有兩個A_b執行個體。

3、singleTask

當一個singleTask 模式的activity 被啟動時,AMS會檢查是否存在與該activity 的taskAffinity 相同的task。

1)如果存在這樣的task,那麼檢查該activity 是否已經建立,如果已建立,那麼銷毀在該Activity 以上的activity 并調用onNewIntent。如果activity 尚未執行個體化,那麼建立該activity 的執行個體,并壓入該task 棧。最後然後将該task 推到最上面。

2)如果不存在這樣的task,那麼就重新建立task,然後建立該activity 的執行個體,并入棧,然後将該task 推到最上面。

Activity啟動模式&Task棧

沒有Home鍵參與

在沒有Home鍵參與的場景下,A_b和B_b是SingleTask的,首先啟動A應用的主界面A_a,然後啟動A_a啟動B應用的B_b,由于B_b是singleTask的,是以建立了新的Task_b。B_b啟動應用A的A_b,由于A_b是singleTask的,是以沒有在Task_b中建立A_b執行個體,而是先查找到A_b對應的Task_a,然後在Task_a中建立A_b執行個體,并将Task_a推到最頂層。

Activity啟動模式&Task棧

home場景1

啟動A應用的主界面A_a,

A_a是singleTask

的,然後啟動了A_b、A_c,這時按下home鍵,接着從前應用A,發現A_a上面的Activity都被彈出棧了。

Activity啟動模式&Task棧

home場景2

場景2中A_b是singleTask的,由于A_b不是rootActivity,是以沒有出現Activity出棧操作。

Activity啟動模式&Task棧

home場景3

首先啟動應用A的主界面A_a,然後啟動A_b,A_b是singleTask的,且taskAffinity和A_a一緻,按下home鍵之後再啟動B應用的主界面B_b,生成可新的Task_b,這時候B_b啟動A_b,由于A_b是singleTask的,是以B_b從Task_a中移除了,Task_a位于頂部了。

Activity啟動模式&Task棧

home場景4

啟動A應用的主界面A_a,位于Task_a中,然後按下home鍵,啟動應用B的主界面B_a,B_a位于Task_b中,這時候B_a啟動B_b,由于B_b是singleTask的,且taskAffinity和A_a的taskAffinity一緻,是以Task_a會推到前台,然後将B_b的執行個體塞入Task_a中。

4、singleInstance

該啟動模式的activity被啟動時,如果activity沒有被執行個體化,就建立一個新的task來儲存activity執行個體;如果已經被執行個體化過,就調用其onNewIntent函數,該activity所在的Task中不允許存在其餘activity。

Activity啟動模式&Task棧

先确定應用A的主界面A_a,然後啟動singleInstance的A_b,這裡就建立了新的Task_b來儲存A_b,然後A_b啟動A_c,由于A_b具有獨占Task的特性,是以需要先查找A_c的taskAffinity(

不設定預設使用包名作為Taskname

)對應的task是否存在,如果不存在就建立新的Task,如果存在就将Task推到前台,這裡将Task_a推到了前台,并将A_c壓入。

5、FLAG_ACTIVITY_NEW_TASK

啟動Activity如果使用這個屬性,AMS會嘗試查找被啟動的Activity的taskAffinity相同的Task,如果有,就直接将Task移動到前台,然後将啟動的Activity壓入棧;如果沒有,則建立一個新的棧來儲存執行個體。

Activity啟動模式&Task棧

繼續閱讀