Activity學(xué)習第二篇
1. LaunchMode
再簡單的東西也需要認真對待。
Activity的四中啟動模式:
- standard:標準模式(默認)
- singleTop: 棧頂復(fù)用模式
- singleTask:棧內(nèi)復(fù)用模式
- singleInstance:單實例模式
首先是 standard ,這是系統(tǒng)默認的啟動模式。
當我們啟動新的Activity時候,是調(diào)用 Context 的startActivity() 方法。
但是,如果這個Context不是Activity類型而是ApplicationContext。那這時候會報錯,無法啟動。因為在standard模式下,是在當前Activity的所屬任務(wù)棧中啟動新的Activity,如果這個Context不是Activity類型的話,那么就不存在所謂的Activity任務(wù)棧了,報錯也就理所當然了。所以這個時候可以配置 ** Flag (FLAG_ACTIVITY_NEW_TASK)**,這時候?qū)嶋H上以singleTask模式啟動。在新的任務(wù)棧中啟動Activity。這樣,就可以使用ApplicationContext啟動Activity。?乛?乛?
再看singleTop,如果這個Activity已經(jīng)存在于這個棧的棧頂,那么就會復(fù)用這個Activity,不會重新創(chuàng)建新的Activity。這個時候Activity 的onCreate() 和 onStart() 不會被調(diào)用。但是會有另一個方法 onNewIntent() 方法被調(diào)用。當配置了singleTop的Activity處于棧頂,又再次被啟動的時候,調(diào)用如下:
然后是singleTask 棧內(nèi)復(fù)用。這種模式下,只要Activity在 某一個棧內(nèi)(可能存在多個棧) 存在,就回復(fù)用這個Activity,而不會去重新創(chuàng)建。和singleTop一樣,系統(tǒng)也會調(diào)用 onNewIntent() 方法。
這里有幾種情況,首先是請求的棧是本棧還是一個新棧,還有就是Activity存不存在。
現(xiàn)在有個Activity棧,有ABC三個Activity。要創(chuàng)建一個新的Activity D。
1. 本Activity棧 — Activity不存在
這種情況最簡單,創(chuàng)建一個新的Activity,壓入棧中即可。這個棧變成了 ABCD。
2. 本Activity棧 — Activity存在
這是如果本棧的Activity 是 ADBC 這個樣子。然后再使用singleTask模式啟動 D 這個Activity。系統(tǒng)會將D 調(diào)到棧頂,并且調(diào)用D的 onNewIntent() 方法。同時會將D上面的所有Activity清除掉。這時棧變成了 AD。
3. 新Activity棧 — Activity不存在
這個時候需要重新創(chuàng)建因為這個棧不存在,這個Activity也存在,所以這時,系統(tǒng)先創(chuàng)建一個棧,然后再創(chuàng)建一個Activity,再將Activity壓入新棧中。
4. 新Activity棧 — Activity存在
這是最復(fù)雜一種情況。這時候會有一個 后臺棧 和 前臺棧 的概念。
先來分析這種情況,當前Activity肯定處于前臺棧,既然新的Activity要在新的棧中啟動,并且Activity已經(jīng)存在,那么,這個棧肯定已經(jīng)創(chuàng)建完成,并且屬于 后臺棧 。這時,系統(tǒng)會先將整個任務(wù)棧調(diào)到前臺,然后再按照singleTask 原則,該復(fù)用復(fù)用,該清除清除。這時整個棧中的所有Activity都會被調(diào)到另一個棧之前。所以,一直按Back鍵,回退的Activity順序會有所改變。
最后是 singleInstance 。一種加強型的singleTask。擁有singleTask的所有特性。不同在于,這個模式的Activity會在一個新的獨特的棧中創(chuàng)建Activity,這個棧中只有這個Activity存在。由于棧內(nèi)復(fù)用的特性,所有的這個Activity啟動時都不會重新創(chuàng)建。除非這個獨特的任務(wù)棧被系統(tǒng)殺死。
2. 任務(wù)棧
這里主要說明兩個配置參數(shù) taskAffinity 和 allowTaskReparenting 。
taskAffinity: 每個Activity都有 taskAffinity 屬性,這個屬性指出了它希望進入的Task。默認情況下,taskAffinity 的值是包名。所以如果你設(shè)置了這個屬性是包名的話,那和沒設(shè)置是一樣的。
<activity android:name=".Act3"
android:taskAffinity="com.mytest.task2"/>
如果想要Activity在新的任務(wù)棧中啟動,那么需要兩步:
- Manifest中設(shè)置Activity的taskAffinity屬性 。
- 在啟動Activity時候需要設(shè)置 FLAG_ACTIVITY_NEW_TASK 。
在Activity中可以使用 Activity. getTaskId() 方法來獲取當前Task的 ID。驗證自己的猜想。
allowTaskReparenting :這個屬性用于設(shè)定Activity能夠從啟動它的任務(wù)中轉(zhuǎn)移到另一個與啟動它的任務(wù)有親緣關(guān)系的任務(wù)中。
這個親緣關(guān)系只能和根Activity去比較,所以必須在根Activity設(shè)置taskAffinity,而需要轉(zhuǎn)移的Activity不需要是根Activity。
如果設(shè)置了true,則能夠轉(zhuǎn)移,如果設(shè)置了false,則這個Activity保留在啟動它的那個任務(wù)中。
設(shè)置方式:
<activity
android:name=".Act2"
android:allowTaskReparenting="true"
android:taskAffinity="com.mytest.task2" />
<activity
android:name=".Act1"
android:taskAffinity="com.mytest.task2"/>
這里比較難理解,舉個例子吧:
現(xiàn)在有兩個應(yīng)用 應(yīng)用A、 應(yīng)用B 。
應(yīng)用A 是在前臺的應(yīng)用,應(yīng)用B是后臺應(yīng)用。
應(yīng)用B 的 Act 1 和 Act 2 有相同的taskAffinity。(這樣就具有了親緣關(guān)系)
應(yīng)用B 的 Act 2 配置了android:allowTaskReparenting="true" 。
現(xiàn)在 應(yīng)用A 啟動應(yīng)用B 的 Act 2。
然后回到桌面,啟動應(yīng)用B 的 Act 1。
流程如下:
其中,Act 2 這個Activity從應(yīng)用A的棧中,轉(zhuǎn)移到了應(yīng)用B的棧的頂端。
(可以將應(yīng)用B 的 Act 2想象成瀏覽器的網(wǎng)頁界面。其他應(yīng)用打開了網(wǎng)頁。這時打開瀏覽器應(yīng)用,那個打開的網(wǎng)頁處于最前端)
還有其他的一些配置屬性,后續(xù)再寫吧。