1. 程式人生 > >你真的明白Task嗎?

你真的明白Task嗎?

1870221-0aa0a2c884eeb7c5.png

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)

1870221-08c82e5c19d04c74.png image.png

返回棧 C -> B -> A

2、SingleTop

2、1
A_acitivty (Standard)
B_activity (Standard)
C_activity (Standard)
B_activity (SingleTop)


1870221-fd008467180e737c.png image.png

返回棧 B -> C -> B -> A

2、2
A_acitivty (Standard)
B_activity (Standard)
C_activity (SingleTop)
C_activity (SingleTop)

1870221-cc1ed83867708f87.png image.png

返回棧 C -> B -> A

我們發現C-> C 複用了C。且呼叫了onNewIntent方法。

3、SingleTask

3.1

A_acitivty (Standard)
B_activity (Standard)
C_activity (SingleTask)


1870221-d3fa2f18303ef85e.png image.png

返回棧 C -> B -> A
這個情景和SingleTop功能一樣。

3.2

A_acitivty (SingleTask)
B_activity (Standard)
C_activity (Standard)
A_activity (SingleTask)


1870221-2766501608b9dda8.png 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);
1870221-37a3a3faf503c70f.png 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);
    }
1870221-620709f942f30695.png image.png

返回棧 C -> C -> B -> A

3.5

A_acitivty (Standard)
B_activity (Standard)
C_activity (SingleTask +FLAF_ACTIVITY_NEW_TASK)


1870221-bb7372a59543bca3.png image.png

怎麼想換個任務棧這麼難呢?書上都是騙人的嗎?不是說好可以換的嗎?
還好我們自己做了實驗,不然你懂得~~呵呵噠。(書上並沒有說錯,只是沒說清楚情況)
那怎麼才能換一個任務棧呢?
這就用到了我們的重點TaskAffinity。

3.6

FLAG_ACTIVITY_NEW_TASK 和 TaskAffinity結合。
如果我們沒有FLAG_ACTIVITY_NEW_TASK只設置TaskAffinity。 結果如下


1870221-a0f8fa756c450a34.png 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"
            />
1870221-28bde8ec51951e5f.png image.png

3.7

那麼當SingleTask和TaskAffinity結合又會發生什麼呢?


1870221-ca2400822d47d2c8.png image.png

多麼神奇的引數啊。所以TaskAffinity只會和四大模式中的SingleTast發生反應。當入棧的Activity是SingleTasK,而且有他的TaskAffinity,所以就會建立一個屬於他的TaskAffinity任務棧,預設任務棧的名字是包名,所以新建立了一個任務棧。

3.8

那麼當我們第一個Activity(SingleTasK)就設定TaskAffinity,後面的Activity還會進來嗎?還是另起一個任務棧呢?


1870221-a4dd5486e191a940.png 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)

1870221-b1cc9323699bab5b.png image.png

返回棧C -> B -> A

SingleInstance很簡單很暴力。那麼如果我們第一個Activity是SingleInstance,後面的是Standard呢?


1870221-302262b908f9e6a7.png image.png

結論是SingleInstance很霸道,任務棧只能有他一個,如果有別的就新啟一個任務棧。

5、TaskAffinity和allowTaskReparenting

5.1
A應用呼叫B應用的C(TaskAffinity,allowTaskReparenting=true)

B:MainActivity(Standard)
A:C_activity (Standard)
Home鍵
點選A應用的Icon,進去


1870221-66e67ffe7424747b.png 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,這個任務棧怎麼說?


1870221-27e7e22e2ee428ec.png image.png

雖然跨應用了,但是還是一個任務棧。沒什麼區別

情況二:B應用的展示介面是C(SingleTop),按Home鍵返回桌面,然後A應用開啟B應用的介面C,這個任務棧怎麼說?


1870221-62c2bf255a63f21e.png image.png

我們會發現,SingleTop跨應用的結論還是一直的的。

情況三:B應用的展示介面是C(SingleTask),按Home鍵返回桌面,然後A應用開啟B應用的介面C,這個任務棧怎麼說?


1870221-64b9070219896720.png image.png

這個其實就觸發了TaskAffinity,C的TaskAffinity預設是B應用的包名,A應用的TaskAffinity預設是A應用的包名,這裡相當於TaskAffinity有了變化,根據SingleTask和TaskAffinity的性質,那麼自然就會新起一個任務棧。

大家如果覺得有幫助的話,可以點個關注,告訴我大家想要深入探究哪些問題,希望看到哪方面的文章,我可以免費給你寫專題文章。。或者私信溝通都可以。。。
希望大家多多支援。。你的一個關注,是我堅持的最大動力。。