-
Activity為什么需要啟動模式?
為了避免頻繁啟動一個Activity時,生成多個實例,杜絕內存浪費。
一個Activity啟動時,這個Activity實例就會被放入任務棧(Task)中; 當點擊返回鍵的時候,位于任務棧頂層的Activity就會被清理出去; 當任務棧中不存在任何Activity實例后,系統就會去回收這個任務棧,程序退出。
-
怎么用
1.通過AndroidMenifest.xml文件為Activity指定啟動模式
<activity android:name=".activity" android:launchMode="standard" />
2.通過在Intent中設置標志位(addFlags方法)來為Activity指定啟動模式
Intent intent = new Intent(); intent.setClass(ActivityB.this,ActivityA.class); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); startActivity(intent);
常用的Activity的Flag
-
Intent.FLAG_ACTIVITY_NEW_TASK
相當于singleTask 通常我們在Service啟動Activity時由于Service中并沒有Activity任務棧, 所以必須使用該Flag來創建一個新的Task.
-
Intent.FLAG_ACTIVITY_SINGLE_TOP
該標志位表示使用singleTop模式來啟動一個Activity
-
Intent.FLAG_ACTIVITY_CLEAR_TOP
該標志位表示使用singleTask模式來啟動一個Activity
-
Intent.FLAG_ACTIVITY_NO_HISTORY
使用該模式來啟動Activity,當該Activity啟動其他Activity后, 該Activity就被銷毀了,不會保留在任務棧中。 如A-B,B中以這種模式啟動C,C再啟動D,則任務棧只有ABD。
-
Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
使用該標識位啟動的Activity不添加到最近應用列表, 也即我們從最近應用里面查看不到我們啟動的這個activity。 與屬性android:excludeFromRecents="true"效果相同。
-
-
taskAffinity 屬性
taskAffinity屬性不對standard和singleTop模式有任何影響
<activity android:name=".ActivitySingleTop" android:launchMode="singleTop" android:taskAffinity="com.castiel.demo.singletop"/>
- 這個參數標示了一個Activity所需任務棧的名字,默認情況下,所有Activity所需的任務棧的名字為應用包名
- 一個任務的affinity決定于這個任務的根activity的taskAffinity
- 具有相同的affinity的activity(即設置了相同taskAffinity屬 性的activity)屬于同一個任務
- 為一個activity的taskAffinity設置一個空字符串,表明這個activity不屬于任何task;
-
Activity的4種啟動模式
-
standard-默認模式
允許多個相同Activity實例創建,疊加;
-
singleTop-棧頂復用模式
如果新的activity已經位于棧頂,那么這個activity不會被重寫創建,同時它的onNewIntent方法會被調用,通過此方法的參數可以去除當前請求的信息;
如果棧頂不存在該activity的實例,則情況與standard模式相同;
-
singleTask-棧內復用模式
模式啟動時會通過taskAffinity屬性尋找任務棧,如果任務棧不存在,最會創建這個任務棧
如果棧中存在這個Activity的實例就會復用這個Activity,復用時,會將它上面的Activity出棧,并調用該實例的onNewIntent
-
singleInstance-全局唯一模式
該模式具備singleTask模式的所有特性外
區別:這種模式下Activity會單獨占用一個Task棧,具有全局唯一性(即整個系統中就這么一個實例),除非這個任務棧銷毀,否則不會創建新的實例
-
應用場景
standard:普通activity
singleTop:適合接收通知啟動的內容顯示頁面
比如一下子收到一堆推送消息,不能每個都彈出來吧。但凡是這樣的都行。優酷的推薦視頻,電商app推送一個活動。
singleTask:程序入口等啟動頁面
最常見的應用場景就是保持我們應用開啟后僅僅有一個Activity的實例。最典型的樣例就是應用中展示的主頁面(Fragment的containerActivity)、WebView頁面、掃一掃頁面、電商中:購物界面,確認訂單界面,付款界面。
singleInstance:完全獨立的
系統Launcher、鎖屏鍵、來電顯示等系統應用;
singleInstance不要用于中間頁面,如果用于中間頁面,跳轉會有問題。
問題:舉例 A -> B(singleInstance) ->C
情形 1:在 C 界面返回,會直接返回到 A,繼續在 A 界面返回(退出) 會 出現 B(singleInstance) 界面。
情形 2:打開 C 界面 ,HOME 鍵應用推到后臺再次返回應用,在 C 界面返回到 A,繼續在 A 界面返回(退出),B被系統殺死不會再出現(設置taskAffinity屬性除外)。
singleInstance用于中間頁面的情形被面試官問到了,思路沒錯,回來試了下確實是這樣無意中發現了情形 2的情況需要進一步驗證原因,這里暫且不議。
LaunchMode與startActivityForResult() 的一些使用問題
在 5.0 之前 可能會遇到這種情況:
startActivityForResult方法啟動一個Activity,然后在onActivityResult()方法中可以接收到上個頁面的回傳值,但你有可能遇到過拿不到返回值的情況。
原因:在還沒有開始界面跳轉本身的onActivityResult被馬上被執行了
官方注解標示:
Android認為不同的Task之間對這種要求返回結果的啟動方式會產生一些依賴(對Task),所以干脆簡單粗暴在跳轉前直接返回RESULT_CANCELED結果。
關系如下:
所以要注意5.0之前對啟動模式的使用
5.0之后沒有這類問題。