你真的明白Task嗎?
LauchMode
對於Activity的LauchMode想必大家都不陌生。
- Standard(標準)
- SingleTop(棧頂複用)
- SingleTask(棧內複用)
- SingleInstance(單例模式)
但是我們真的懂如何運用,或者這些Mode設計的原因是解決什麼目的嗎?概念總是很單薄,看的似懂非懂。所以我們需要通過場景去了解這些東西本質。才不會看了忘,忘了看,無限迴圈。
1、Standard
每次啟動Activity都會建立一個新的例項,不管任務棧裡面是否有。
注意:平時我們啟動Activity都是在Activity裡,但是當我們在Service或者Receiver中,我們呼叫的是Service和Receiver的Context,他們並不是Activity沒有任務棧,那怎麼辦呢?新增FLAF_ACTIVITY_NEW_TASK標記位,那麼它是否還新啟動一個任務棧,還是沿用原來的呢?需要分情況分析,下邊講解FLAF_ACTIVITY_NEW_TASK會說明的。
2、SingleTop
位於任務棧
棧頂的的Activity,再次啟動的時候不需要重新建立。如果不在棧頂,那麼就需要重新建立了。看名字就知道,只能在棧頂複用。
注意:我們重新複用的這個Activity的onCreate和onStart不會被系統呼叫,但是會呼叫onNewIntent這個回撥,我們可以從這個方法裡面獲取data資訊。比如getIntent()等等。
3、SingleTask
這個是重點也是難點,一定要注意這個。
棧內複用,只要Task任務棧裡存在這個Activity,那麼當重新啟動這個Activity的時候就會複用,複用細節和SingleTop一致。預設具有clearTop作用。當Task任務棧裡從底到頂分別是acitivty :ABCD,當B(LauchMode=SingleTask)再次啟動的時候,他會進行復用,在複用的同時,會把它上面的Activity都清理掉,任務棧就變成了AB。
通過FLAF_ACTIVITY_NEW_TASK標誌位啟動的Activity會被賦值為SingleTask,並且會新建一個任務棧。
4、SingleInstance
單例模式,加強版的SingleTask,SingleTask有的他都有,而且比SingleTask還要霸道,具有此模式的Activity只能單獨位於一個任務棧。當該Activity啟動後,再次啟動都是複用。
TaskAffinity
講完四大啟動模式,我們要講taskAffinity,這是重點也是難點。
TaskAffinity可以翻譯成 任務相關性,標誌了一個Acitivty所需要的任務棧的名字。
TaskAffinity一般是和singleTask 或者allowTaskReparenting配對使用,在其他情況下也沒什麼作用,所以我們重點看這兩個配對的使用。
1、TaskAffinity和singleTask
TaskAffinity是具有這個模式的activity的目前任務棧的名字。
待啟動的Activity會執行在名字和TaskAffinity一樣的任務棧中。
就是說當這個Activity(明確了TaskAffinity)是第一個的時候,會把這個任務棧命名成他TaskAffinity的名字。後續的未特殊處理的Activity都會進入這個棧。
當這個Activity(明確了TaskAffinity)不是第一個,他前面有一個棧而且裡面有Activity,那麼因為TaskAffinity不同(預設是包名)那麼這個activity會新啟一個任務棧命名為他的TaskAffinity,後續的Activity會進入他的任務棧。
2、TaskAffinity和allowTaskReparenting
舉個例子:
如果A應用啟動了B應用的介面(Activity) C,C的allowTaskReparenting=true,按Home鍵,回到主介面,然後我們在點選B應用的桌面圖示開啟B應用,我們發現,顯示的並不是B的主Activity,而是C Activity,C的任務棧從A轉移到了B。
分析:
因為A啟動了C,所以C的任務棧在A,但是C是屬於B的(記住這一點),因為C的TaskAffinity是和A任務棧的TaskAffinity是不同的,所以當B啟動的時候,B會建立B任務棧,當C發現B的TaskAffinity和他的一樣,然後就會從A任務棧中跑道B任務棧。
有意思的結論:
你撿了一條狗,好吃好喝的喂著,他也把這裡當家了,但是有一天它的主人來了,他就屁顛屁顛跟著它的主人走了。
實驗
當我們把這些結論寫出來的時候,其實大多數人還是懵逼的,為什麼呢?缺乏實際情景,還是不知道怎麼應用?
我們就一一做實驗,用資料和情景來學習這些知識。
順序從上到下
1、Standard
A_acitivty (Standard)
B_activity (Standard)
C_activity (Standard)
返回棧 C -> B -> A
2、SingleTop
2、1
A_acitivty (Standard)
B_activity (Standard)
C_activity (Standard)
B_activity (SingleTop)
image.png
返回棧 B -> C -> B -> A
2、2
A_acitivty (Standard)
B_activity (Standard)
C_activity (SingleTop)
C_activity (SingleTop)
返回棧 C -> B -> A
我們發現C-> C 複用了C。且呼叫了onNewIntent方法。
3、SingleTask
3.1
A_acitivty (Standard)
B_activity (Standard)
C_activity (SingleTask)
image.png
返回棧 C -> B -> A
這個情景和SingleTop功能一樣。
3.2
A_acitivty (SingleTask)
B_activity (Standard)
C_activity (Standard)
A_activity (SingleTask)
image.png
返回棧 A
把棧頂BC都清理了。
3.3
A_acitivty (Standard)
B_activity (Standard)
C_activity (Standard+FLAF_ACTIVITY_NEW_TASK)
C_activity (Standard)
blic void onClick(View v) {
Intent intent = new Intent(B_Activity.this,C_Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
image.png
返回棧 C -> C -> B -> A
我們發現並沒有出現我們所想的那樣,還是在一個任務棧
然後我們換個做法
3.4
A_acitivty (Standard)
B_activity (Standard)
MyService(FLAF_ACTIVITY_NEW_TASK)
C_activity (Standard)
@Override
public void onCreate() {
super.onCreate();
Intent intent1 = new Intent(getApplicationContext(), C_Activity.class);
intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
getApplicationContext().startActivity(intent1);
}
image.png
返回棧 C -> C -> B -> A
3.5
A_acitivty (Standard)
B_activity (Standard)
C_activity (SingleTask +FLAF_ACTIVITY_NEW_TASK)
image.png
怎麼想換個任務棧這麼難呢?書上都是騙人的嗎?不是說好可以換的嗎?
還好我們自己做了實驗,不然你懂得~~呵呵噠。(書上並沒有說錯,只是沒說清楚情況)
那怎麼才能換一個任務棧呢?
這就用到了我們的重點TaskAffinity。
3.6
FLAG_ACTIVITY_NEW_TASK 和 TaskAffinity結合。
如果我們沒有FLAG_ACTIVITY_NEW_TASK只設置TaskAffinity。 結果如下
image.png
當我們給Activity設定了TaskAffinity,並且設定了FLAG_ACTIVITY_NEW_TASK引數
Intent intent = new Intent(B_Activity.this, C_Activity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
<activity android:name=".C_Activity"
android:taskAffinity=".CCC"
/>
image.png
3.7
那麼當SingleTask和TaskAffinity結合又會發生什麼呢?
image.png
多麼神奇的引數啊。所以TaskAffinity只會和四大模式中的SingleTast發生反應。當入棧的Activity是SingleTasK,而且有他的TaskAffinity,所以就會建立一個屬於他的TaskAffinity任務棧,預設任務棧的名字是包名,所以新建立了一個任務棧。
3.8
那麼當我們第一個Activity(SingleTasK)就設定TaskAffinity,後面的Activity還會進來嗎?還是另起一個任務棧呢?
image.png
結論是 後面的Activity會進來這個任務棧。
FLAG_ACTIVITY_NEW_TASK
通過以上資料研究得出以下結論:
首先判斷是否有與被啟動的Activity
相同的相關性
的任務棧
,如果有,那麼就不會重新啟動一個任務棧。如果沒有那麼就需要重新啟動一個任務棧了。
FLAG_ACTIVITY_NEW_TASK和SingleTask引數 是否開啟新棧都與TastAffnity有關係,TastAffnity相同不會開啟新棧,不同就會開啟新棧。
4、SingleInstance
A_acitivty (Standard)
B_activity (Standard)
C_activity (SingleInstance)
返回棧C -> B -> A
SingleInstance很簡單很暴力。那麼如果我們第一個Activity是SingleInstance,後面的是Standard呢?
image.png
結論是SingleInstance很霸道,任務棧只能有他一個,如果有別的就新啟一個任務棧。
5、TaskAffinity和allowTaskReparenting
5.1
A應用呼叫B應用的C(TaskAffinity,allowTaskReparenting=true)
B:MainActivity(Standard)
A:C_activity (Standard)
Home鍵
點選A應用的Icon,進去
image.png
我們發現,B應用開啟啟動主ActivityMainActivity,點選跳轉A應用的C_activity。然後home鍵退出B應用,再點選啟動A應用,但是A應用並沒有開啟他的主Activity(A_activity)而是又打開了C_activity。我們發現雖然都是同一個C_activity,但是任務棧變了。變成了B的任務棧,但是C_activity還是那個C_activity。
這就是著名結論:
你撿了一條狗,好吃好喝的喂著,他也把這裡當家了,但是有一天它的主人來了,他就屁顛屁顛跟著它的主人走了。
6、其他情況
如果是A應用,啟動了B應用的介面C
情況一:B應用的展示介面是C(Standard),按Home鍵返回桌面,然後A應用開啟B應用的介面C,這個任務棧怎麼說?
image.png
雖然跨應用了,但是還是一個任務棧。沒什麼區別
情況二:B應用的展示介面是C(SingleTop),按Home鍵返回桌面,然後A應用開啟B應用的介面C,這個任務棧怎麼說?
image.png
我們會發現,SingleTop跨應用的結論還是一直的的。
情況三:B應用的展示介面是C(SingleTask),按Home鍵返回桌面,然後A應用開啟B應用的介面C,這個任務棧怎麼說?
image.png
這個其實就觸發了TaskAffinity,C的TaskAffinity預設是B應用的包名,A應用的TaskAffinity預設是A應用的包名,這裡相當於TaskAffinity有了變化,根據SingleTask和TaskAffinity的性質,那麼自然就會新起一個任務棧。
大家如果覺得有幫助的話,可以點個關注,告訴我大家想要深入探究哪些問題,希望看到哪方面的文章,我可以免費給你寫專題文章。。或者私信溝通都可以。。。
希望大家多多支援。。你的一個關注,是我堅持的最大動力。。