launchmode的四種模式,不需要細說:standard、singleTop、singleTask、singleInstance。
此博客關注的是,關於Activity中關於Affinity(親和力)&Intent標記的東西,即使是Android老鳥,也不一定將其中的細節理解透徹。
使用Intent啟動一個Activity,有如下標記:
1、FLAG_ACTIVITY_NEW_TASK
2、FLAG_ACTIVITY_CLEAR_TOP
3、FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
4、FLAG_ACTIVITY_SINGLE_TOP
使用最多的,當然是FLAG_ACTIVITY_NEW_TASK。
主要的Activity屬性有:
1、taskAffinity
2、launchMode
3、allowTaskReparenting
4、clearTaskOnLaunch
5、alwaysRetainTaskState
6、finishOnTaskLaunch
當Affinity與LaunchMode結合起來使用,就比較讓人蛋疼的事情了。在實際項目中,靈活使用各種屬性,可以讓程序運行流暢,界面直接的導航跳轉流暢,用戶體驗良好。反之,則讓人摸不著頭腦,讓人蛋疼。絕知此事須躬行的道理,才油然而生。
關於上述的各種屬性,可以參看Google文檔,Tasks and Back Stack ,文檔中將各種情況分析得較為全面,網上的資料,均是翻譯其內容。
FLAG_ACTIVITY_NEW_TASK 講解:
case 1:當Intent對象包含這個標記時,系統會尋找或創建一個新的task來放置目標Activity,尋找時依據目標Activity的taskAffinity屬性進行匹配,如果找到一個task的taskAffinity與之相同,就將目標Activity壓入此task中。
case 2:如果查找無果,則創建一個新的task,並將該task的taskAffinity設置為目標Activity的taskActivity,將目標Activity放置於此task。
上面的兩個case,可以簡單的理解為:
FLAG_ACTIVITY_NEW_TASK標記,不一定會啟動一個新的棧,其策略是:先查找有沒有和這個Activity的affinity相同的task棧,如果有,則直接在這個task棧裡啟動,沒有才創建一個新的task棧。
case 3:如果同一個應用中Activity的taskAffinity都使用默認值或都設置相同值時,應用內的Activity之間的跳轉使用這個標記是沒有意義的,因為當前應用task就是目標Activity最好的宿主。
為了更好的說明其中的扯淡關系,使用案例進行說明上述的case 1、case 2、case 3
一個簡單的app中,MainActivity點擊按鈕啟動一個新的Activity。
case 1:在AndroidManifest.xml中定義的屬性為:
... .... .... ....
app運行效果如下:
在OtherActivity界面,多次點擊“Start AppOther OtherActivity in AppOther”按鈕,會啟動多個Activity Instance,由於兩個Activity擁有共同的taskAffinity,將處於同一個task裡面。
case 2:在AndroidManifest.xml中定義的屬性為:
app運行效果如下:
在OtherActivity界面,點擊“Start AppOther OtherActivity in AppOther”按鈕,創建新的Activity Instance,由於兩個Activity擁有的taskAffinity不同,新的instant將處於另外的task裡面,其task id 為23.
PS:此處多次點擊點擊“Start AppOther OtherActivity in AppOther”按鈕,不會產生新的Activity Instance。
在case 2中,當界面停留在OtherActivity時,此時按Home鍵,讓app進入後台運行,再次啟動app,將直接顯示MainActivity界面,而不是OtherActivity界面。主要原因是,該app的啟動時,系統將尋找root Activity所處的那個task,而該app的root activity為MainActivity,所以顯示MainActivity界面。
case 3:在AndroidManifest.xml中定義的屬性為與case 1一致。
此時Activity之間的導航,與普通的跳轉一致,task的創建與否,直接根據launchMode來確定。
allowTaskReparenting講解:
這個屬性用來標記一個Activity實例在當前應用退居後台後,是否能從啟動它的那個task移動到有共同affinity的task,“true”表示可以移動,“false”表示它必須呆在當前應用的task中,默認值為false。
如果一個Activity的元素沒有設定此屬性,則為默認方式。繼續用demo進行演示,進行深入淺出的分析。
應用TaskAffinity的MainActivity中,點擊按鈕,進入應用AppOther的OtherActivity,其對應AndroidManifest.xml中定義的屬性如下:
TaskAffinity的AndroidManifest.xml
AppOther的AndroidManifest.xml
首先運行TaskAffinity應用,啟動界面如下:
點擊“Start AppOther OtherActivity”按鈕,執行如下的代碼:
Intent intent = new Intent("android.intent.action.AppOther_OTHER_ACTIVITY");
startActivity(intent);
將啟動AppOther中的OtherActivity界面,效果如下:
兩個Activity的task id 一致,表明是在同一個task裡面。此時,按下“Home”鍵,顯示主屏,之後再菜單中點擊TaskAffinity應用圖標,啟動之後,界面如下:
依舊顯示的是AppOther應用的OtherActivity界面。
由此demo,了解到,不同應用的Activity,可以處於同一個task裡面,並且使用默認的allowTaskReparenting屬性,其task在由後台轉入前台時,不會從task remove。
示例將做小小改動,修改AppOther中OtherActivity的屬性,將allowTaskReparenting置為true,其他的代碼,不做任何修改,AndroidManifest.xml如下:
運行後,效果圖如下:
TaskAffinity應用圖 點擊按鈕,啟動OtherActivity圖 按下home鍵後,再次TaskAffinity圖
從上述示例,可以得知,android:allowTaskReparenting="true",對於Activity的作用了。