在平常開發過程當中,只要涉及到activity,那麼對task相關的東西總會或多或少的接觸到,不過對task相關的一些配置的做用一直理解的還不是很透徹,官方文檔在細節上說的也不夠清楚,要透徹理解仍是得本身寫demo實踐檢驗,因此便有了這篇總結。html
task的概念
參考Tasks and Back Stackandroid
查看設備當前task的方法
AndroidManifest中activity標籤下和task有關的屬性
- 此屬性用來標記activity應該屬於哪一個task。
- 擁有相同affinity的activity從理論上屬於同一個task(在用戶的角度看來好像這些activity屬於同一個應用),一個task的affinity是由其根activity的taskAffinity取值決定的。
- affinity決定了兩件事。
- 一個是在使用allowTaskReparenting修飾activity時,activity要從新宿主到哪一個task。
- 另外一個是使用FLAG_ACTIVITY_NEW_TASK啓動activity時,activity要放入哪一個task。
- 若是沒有給activity設置taskAffinity,默認都會讀取application標籤下的taskAffinity屬性值,若是application標籤下也沒有設置taskAffinity,那taskAffinity默認值就是manifest標籤下設置的包名。
- 不只能夠給同一個應用的不一樣activity設置不一樣的affinity,也能夠給不一樣應用的activity設置相同的affinity,使它們在用戶角度看來好像屬於同一個應用。
launchMode有四種取值,與Intent裏以FLAG_ACTIVITY_
開頭的flag結合,能夠對activity的啓動達到各類不一樣的效果。瀏覽器
standard
activity默認的啓動模式,每次啓動一個standard模式的activity時,都新建一個實例。app
singleTop
當前task棧頂存在本activity的實例,直接使用該實例,調用該activity的onNewIntent(),不然新建一個activity的實例入棧。ide
singleTask
當啓動一個singleTask模式的activity時,首先會檢查是否存在與該activity的taskAffinity相同的task。ui
- 若是存在,那麼檢查該task棧裏是否存在該activity實例。
- 若是存在,則將該task調入前臺,銷燬在該activity以上的activity,並調用該activity的onNewIntent()。
- 若是不存在,則新建一個該activity實例,併入棧。
- 若是不存在,則新建一個task,再新建該activity實例並放入新建的task中。
- 從該activity再啓動其餘activity,容許其餘activity跟本身處於同一個task棧中,也容許其餘activity從新宿主到本activity。
例若有四個activity叫A、B、C、D,其中A、B具備相同的affinity,如今taskA裏有A、B,其中A和B是standard。.net
- 從B啓動C,C是singleTask,C的affinity和A、B相同,C會進入taskA棧頂。
- 從C啓動D,D是standard或singleTop,不論D的affinity是什麼,D會進入taskA棧頂。
- 從D啓動C,D出棧被銷燬,C接收到onNewIntent()
- 從C啓動D,D是singleTask,D的affinity和A、B、C相同,D會進入taskA棧頂。
- 從D啓動C,D出棧被銷燬,C接收到onNewIntent()
- 從C啓動D,D是singleTask,D的affinity和A、B、C不一樣,D會進入新建的taskB中。
- 從D啓動C,taskA調入前臺,放在taskB的上面,C接收到onNewIntent()
- 從C啓動D,D是singleInstance,D的affinity不管是什麼,D會進入新建的taskB中,taskB的affinity爲D的affinity。
- 從D啓動C,taskA調入前臺,放在taskB的上面,C接收到onNewIntent()
- 從B啓動C,C是singleTask,C的affinity和A、B不一樣,C會進入新建的taskB中。
- 從C啓動D,D是standard或singleTop,不論D的affinity是什麼,D會進入taskB棧頂。
- 從D啓動C,D出棧被銷燬,C接收到onNewIntent()
- 從C啓動D,D是singleTask,D的affinity和A、B相同,D會進入taskA棧頂。
- 從D啓動C,taskB調入前臺,放在taskA的上面,C接收到onNewIntent()
- 從C啓動D,D是singleTask,D的affinity和A、B不一樣但與C相同,D會進入新建的taskB棧頂。
- 從D啓動C,D出棧被銷燬,C接收到onNewIntent()
- 從C啓動D,D是singleTask,D的affinity和A、B不一樣且與C也不一樣,D會進入新建的taskC中。
- 從D啓動C,taskB調入前臺,放在taskC的上面,C接收到onNewIntent()
- 從C啓動D,D是singleInstance,D的affinity不管是什麼,D會進入新建的taskC中,taskC的affinity爲D的affinity。
- 從D啓動C,taskB調入前臺,放在taskC的上面,C接收到onNewIntent()
singleInstance
當啓動一個singleInstance的activity時,首先會檢查是否存在與該activity的taskAffinity相同的task。翻譯
- 若是存在,檢查這個task中是否存在該activity的實例。
- 若是存在,則將該task調入前臺,並調用該activity實例的onNewIntent()。
- 若是不存在,則新建一個task,再新建該activity實例放入新建的task中,系統容許多個相同affinity的task同時存在。
- 若是不存在,則新建一個task,再新建該activity實例並放入新建的task中。
- 從該activity再啓動其餘任何activity,都會放到其餘task中(新建task或者尋找已存在的task,即便要啓動的activity與該activity具備相同的affinity),也不容許其餘activity宿主到本task,該activity是task中惟一的activity。
例若有四個activity叫A、B、C、D,其中A、B具備相同的affinity,如今taskA裏有A、B,其中A和B是standardexcel
- 從B中啓動C,C是singleInstance,C的affinity和A、B相同,C會放入新建的taskB中,taskA和taskB的affinity相同,由於兩個task的根activity的affinity相同。
- 從C中啓動D,D的affinity和A、B、C相同。
- D是standard、singleTop、singleTask時,D會放入taskA中,taskA調入前臺,放在taskB上面。
- D是singleInstance,D會進入新建的taskC中,taskC和taskA、taskB的affinity相同,由於三個task的根activity的affinity相同。
- 從C中啓動D,D的affinity和A、B、C不一樣,不論D是何種launchMode,D都會進入新建的taskC中,taskC的affinity是D的affinity。
- 從B中啓動C,C是singleInstance,C的affinity和A、B不一樣,C會放入新建的taskB中,taskA和taskB的affinity不一樣,由於兩個task的根activity的affinity不一樣。
- 從C中啓動D,D的affinity和A、B相同。
- D是standard、singleTop、singleTask時,D都會進入taskA中,taskA調入前臺,放在taskB上面。
- D是singleInstance,D會進入新建的taskC中,taskC和taskA的affinity相同,由於兩個task的根activity的affinity相同。
- 從C中啓動D,D的affinity和A、B不一樣,不論和C是否相同,D都會進入新建的taskC中,由於C所在的task不容許其餘activity的存在,taskC的affinity爲D的affinity。
使用場景:
使用singleInstance時,儘可能給此activity設置單獨的taskAffinity,以保證此activity處於不一樣名的task中,這樣在「最近應用」的列表中能夠看到這個task。不然若是有相同task名稱的task存在,在「最近應用」的列表中就看不到這個含有singleInstance的activity的task了,只能經過代碼啓動這個activity來切換回這個task中。
而兩個不一樣的task在用戶角度來看是兩個不一樣的應用,也就是兩種不一樣的功能,因此使用singleInstance的activity功能上要與其餘activity的功能區別較大。而且singleInstance是單例,也就是這個activity是公用的,能夠在其餘地方啓動它來重複使用(能夠是被同一個應用的其餘地方重複使用,也能夠是被其餘的應用重複使用)。
例如,UC瀏覽器中有一個能夠瀏覽office文檔的activity(launchMode爲singleInstance,taskAffinity也是獨立的),這顯然不是瀏覽器的主要功能。在文件管理器中點擊一個excel文件(或者word、ppt文檔)的時候,能夠選擇使用UC瀏覽器的這個activity來打開它,而且從用戶角度看起來這個activity和UC瀏覽器是兩個不一樣的應用(在「最近應用」的列表中能夠看出來)。code
此屬性爲true的activity被啓動後,如有和此activity相同affinity的task轉入前臺,則此activity會從啓動它的task移動到具備相同affinity的這個task。
例如,如今有兩個應用分別爲appA和appB,appA中有三個activity分別爲activityA一、activityA二、activityA3,其中activityA一、activityA2的taskAffinity爲taskA,activityA3的taskAffinity爲taskB,appB中有一個activity爲activityB1,其taskAffinity爲taskB。全部activity都是standard模式。
啓動appA,默認啓動activityA1,再依次啓動activityA二、activityA3,此時這三個activity都屬於taskA。
按home鍵回到launcher,此時這三個activity扔都屬於taskA。
- 此時若點擊appA的圖標啓動appA,看到的是activityA2,activityA3會進入新建的affinity爲taskB的task中。此時全部task的順序由前到後依次爲taskA、Launcher所在的task、taskB。
- 按home鍵回到launcher,點擊appB的圖標啓動appB,taskB調入前臺顯示,看到的是activityA3,而不是activityB1。此時全部task的順序由前到後依次爲taskB、Launcher所在的task、taskA。
- 此時若點擊appB的圖標啓動appB,看到的是activityA3,activityA3進入新建的affinity爲taskB的task中。此時全部task的順序由前到後依次爲taskB、Launcher所在的task、taskA。taskB中還有activityB1在棧底部,在activityA3中按返回鍵能夠回到activityB1。taskA中僅剩activityA一、activityA2。
若是用戶離開一個task已經好久了,系統會在某個時刻清理掉這個task中除了根activity外全部的activity。當用戶再次回到這個task,只有根activity被恢復。這樣作是由於長期離開一個task,用戶頗有可能已經放棄了他以前所作的事情,轉而要開始作新的事情,因此只保留根activity。
若根activity上的alwaysRetainTaskState爲true,強制保留本task中的全部activity,即便過了很長時間,也不讓系統清理task。
例如瀏覽器打開了不少個tab頁,長時間不操做後也要保證再次回來時仍是上次瀏覽的頁面。
與alwaysRetainTaskState相反,若根activity上的clearTaskOnLaunch爲true,不論什麼時候用戶再次從Launcher回到這個task時,除了根activity之外的其餘activity都銷燬。
此屬性爲true的activity,不論什麼時候用戶再次回到這個activity所屬的task時,此activity會被銷燬。此屬性優先級優於allowTaskReparenting。
Intent中和task有關的部分flag
和launchMode的屬性值singleTask等效。若是一個Intent中包含此flag,嘗試將要啓動的activity放在一個新的task中,若是已經有一個task棧裏存在目標activity的實例,將此task從後臺調到前臺來,調用已存在的activity實例的onNewIntent()方法。此flag不能用於startActivityForResult()。
和launchMode的屬性值singleTop等效。若是一個Intent中包含此屬性,而且要啓動的Activity就是當前的Activity(當前task棧頂activity),直接調用該activity的onNewIntent(),不然新建一個activity實例。
若是一個Intent中包含此屬性,而且當前task棧存存在目標activity的實例,清除該實例上面的全部的activity。
若是目標activity的launcherMode爲standard,且Intent沒有添加FLAG_ACTIVITY_SINGLE_TOP標記,則會銷燬目標activity再從新建立,不然會重用該實例,調用onNewIntent()。
若是一個Intent中包含此屬性,則它轉向的那個Activity以及在那個Activity其上的全部Activity都會在task重置時被清除出task,這隻發生在task重置的時候,而從Launcher中點擊應用圖標啓動應用的時候會發生task重置(從Launcher啓動應用會在Intent中附帶一個FLAG_ACTIVITY_RESET_TASK_IF_NEEDED標記)。
參考資料