android中activity設定標誌FLAG_ACTIVITY_NEW_TASK,FLAG_ACTIVITY_CLEAR_TOP詳解和taskAffinity引發的有趣問題

來源:互聯網
上載者:User

今天解決一個比較有意思的問題

問題描述,假設有一個application中包含兩個activity A和B,此時先開啟A 然後按Home鍵退回到MainHome,在framework中回退mainHome是通過startActivity方式開啟mainHome的(我們的android platform是自己定製的,對按鍵重新設計,可能和原生系統不一樣),然後通過一個HotKey(就是一個外設的某一個按鍵)開啟B,開啟檔案為StartActivity 設定兩個Flag 分別是 FLAG_ACTIVITY_CLEAR_TOP和FLAG_ACTIVITY_NEW_TASK,此時奇怪的事情就發生了,當B被開啟後,我們按back鍵回退,回退的地方竟然是A
而不是MainHome。如果我們換一種開啟B的方式,不設定上面的兩個Flag,那麼從B就可以正常回退到MainHome,那麼問題顯然是出在了兩個設定標誌的地方上。然後翻閱文檔和API。

將資料貼上:

FLAG_ACTIVITY_NEW_TASK:

一個Activity一般通過調用startActivity()啟動並加入到Task中。它同調用者一樣,進入同一個Task。
   然而,如果傳遞給startActivity()的Intent對象中包含FLAG_ACTIVITY_NEW_TASK時,系統會搜尋一個新的Task來容納新的Activity。
   通常,如標誌的名字所示,是一個新的Task。然而,並不是必須是。如果已經存在一個Task與新Activity的affinity相同,這個Activity就會加入到那個Task中。如果不是,啟動一個新的Task。
  如果啟動它的acitve和新Activity的affinity相同,那麼新Activity的會進入啟動它的acitve所在的Task.

FLAG_ACTIVITY_CLEAR_TOP:

 如果設定,並且這個Activity已經在當前的Task中運行,因此,不再是重新啟動一個這個Activity的執行個體,而是在這個Activity上方的所有Activity都將關閉,然後這個Intent會作為一個新的Intent投遞到老的Activity(現在位於頂端)中。
    例如,假設一個Task中包含這些Activity:A,B,C,D。如果D調用了startActivity(),並且包含一個指向Activity B的Intent,那麼,C和D都將結束,然後B接收到這個Intent,因此,目前stack的狀況是:A,B。
    上例中正在啟動並執行Activity B既可以在onNewIntent()中接收到這個新的Intent,也可以把自己關閉然後重新啟動來接收這個Intent。如果它的啟動模式聲明為 “standard”(預設值),
    並且你沒有在這個Intent中設定FLAG_ACTIVITY_SINGLE_TOP標誌,那麼它將關閉然後重新建立;對於其它的啟動模式,或者在這個Intent中設定FLAG_ACTIVITY_SINGLE_TOP標誌,都將把這個Intent投遞到當前這個執行個體的onNewIntent()中。
    這個啟動模式還可以與FLAG_ACTIVITY_NEW_TASK結合起來使用:用於啟動一個Task中的根Activity,它會把那個Task中任何啟動並執行執行個體帶入前台,然後清除它直到根Activity。這非常有用,例如,當從Notification Manager處啟動一個Activity

 

也就是說對我們上例啟決定性作用的是FLAG_ACTIVITY_NEW_TASK這個flag.

原因是,當我們的開啟B時,因為使用了new_task屬性,所以系統就會為B尋找一個最具
affinity的activity(也就是A)如果找到了,系統會將此activity(也就是A)設定為前台狀態,就是background,然後將B歸併到A的Task中去,並且壓入頂(如果B之前已經存在於A的Task中那麼CLEAR_TOP屬性將會把B之上得所有activity清除掉,然後將B壓入棧頂).問題分析到這裡,應該已經很清楚了,也就是說A和B一定具有相同的affinity,查閱文檔發現,因為A和B存在於同一個.apk下也就是同一個package下,所以預設具有相同的affinity.下面貼上affinity的相關文檔:

    什麼是Affinity

在某些情況下,Android需要知道一個Activity屬於哪個Task,即使它沒有被啟動到一個具體的Task裡。這是通過任務共用性(Affinities)完成的。任務共用性(Affinities)為這個運行一個或多個Activity的Task提供了一個獨特的靜態名稱,預設的一個活動的任務共用性(Affinity)是實現了該Activity的.apk包的名字。

當開始一個沒有 Intent.FLAG_ACTIVITY_NEW_TASK標誌的Activity時,任務共用性affinities不會影響將會運行該新活動的 Task:它總是運行在啟動它的Task裡。但是,如果使用了NEW_TASK標誌,那麼共用性(affinity)將被用來判斷是否已經存在一個有相同共用性(affinity)的Task。如果是這樣,這項Task將被切換到前面而新的Activity會啟動於這個Task的頂層。

這種特性在您必須使用NEW_TASK標誌的情況下最有用,尤其是從狀態列通知或案頭捷徑啟動活動時。結果是,當使用者用這種方式啟動您的應用程式時,它的當前Task將被切換到前台,而且想要查看的Activity被放在最上面。

你可以在程式清單(Manifest)檔案的應用程式application標籤中為.apk包中所有的活動分配你自己的任務共用性Affinites,或者在主動標記中為各個活動進行分配。

在前面的文章“Android四種Activity的載入模式”我們提到:Activity的載入模式受啟動Activity的Intent對象中設定的Flag和manifest檔案中Activity的<activity>元素的特性值互動控制。


跟 Task 有關的 manifest檔案中Activity的特性值介紹

android:allowTaskReparenting
    用來標記Activity能否從啟動的Task移動到有著affinity的Task(當這個Task進入到前台時)

  “true”,表示能移動,“false”,表示它必須呆在啟動時呆在的那個Task裡。

    如果這個特性沒有被設定,設定到<application>元素上的allowTaskReparenting特性的值會應用到Activity上。預設值為“false”。

    一般來說,當Activity啟動後,它就與啟動它的Task關聯,並且在那裡耗盡它的整個生命週期。噹噹前的Task不再顯示時,你可以使用這個特性來強制Activity移動到有著affinity的Task中。典型用法是:把一個應用程式的Activity移到另一個應用程式的主Task中。
    例如,如果 email中包含一個web頁的連結,點擊它就會啟動一個Activity來顯示這個頁面。這個Activity是由Browser應用程式定義的,但是,現在它作為email Task的一部分。如果它重新宿主到Browser Task裡,當Browser下一次進入到前台時,它就能被看見,並且,當email Task再次進入前台時,就看不到它了。

   Actvity的affinity是由taskAffinity特性定義的。Task的affinity是通過讀取根Activity的affinity 決定。因此,根Activity總是位於相同affinity的Task裡。由於啟動模式為“singleTask”和“singleInstance”的Activity只能位於Task的底部,因此,重新宿主只能限於“standard”和“singleTop”模式。

android:alwaysRetainTaskState
    用來標記Activity所在的Task的狀態是否總是由系統來保持。

    “true”,表示總是;“false”,表示在某種情形下允許系統復原Task到它的初始化狀態。預設值是“false”。

    這個特性只針對Task的根Activity有意義;對其它Activity來說,忽略之。 
    一般來說,特定的情形如當使用者從主畫面重新選擇這個Task時,系統會對這個Task進行清理(從stack中刪除位元於根Activity之上的所有Activivity)。典型的情況,當使用者有一段時間沒有訪問這個Task時也會這麼做,例如30分鐘。
    然而,當這個特性設為“true”時,使用者總是能回到這個Task的最新狀態,無論他們是如何啟動的。這非常有用,例如,像Browser應用程式,這裡有很多的狀態(例如多個開啟的Tab),使用者不想丟失這些狀態。

       所以最終的解決方式就是為B或者A設定不同的affinity這樣A 就不會被吸引到background狀態了,而B 也會在另外的Task中開啟。在B中按back鍵就會返回到MainHome介面。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.