Activities and Tasks --Dev Guide

就像前面提到的,一個activity可以啓動另一個,包括那些定義在不同應用程序中的。假設,例如,你想讓用戶顯示一些地方的街道地圖。已經有一個activity可以做這個事,所以你的activity所要做的就是將行爲對象和需要的信息放在一起,並將它們傳遞給startActivity()。 地圖查看器將顯示這個地圖。當用戶按下後退按鈕時,你的activity又重新顯示在屏幕上了。
    對用戶來說,這個地圖查看器看起來就像是你的應用程序的一部分,即使它定義在另外的應用程序中並運行在那個程序的進程中。Android 通過保持所有的activity在同一個任務中來保持用戶體驗。簡單的的說,任務就是用戶所體驗到的“應用程序”。它是一組相關的activity,分配到一個棧中。棧中的根activity,是任務的開始——一般來說,它是用戶組應用程序加載器中選擇的activity。在棧頂的activity正是當前正在運行的——集中處理用戶動作的那個。當一個activity啓動了另外一個,這個新的activity將壓入棧中,它將成爲正在運行中的 activity。前一個activity保留在棧中。當用戶按下後退按鍵,當前的這個activity將中棧中彈出,而前面的那個activity恢復成運行中狀態。
     棧包含了對象,如果一個棧有多於一個相同的Activity的子類的實例打開——比如,多個地圖查看器——這個棧分別擁有每個實例的入口。棧中的activity不能重新排列,只能壓入和彈出。
    任務是一些activity組成的棧,不是清單文件中的類或元素。所以沒有辦法在獨立於它包含的activity的條件下,設置它的值。任務的值作爲一個整體設置在根activity中。例如,下一節將討論“任務的親和性”;這個值是從根activity親和性中讀取出來的。

    一個任務中的所有activity一起作爲一個單元。整個任務(整個activity棧)可以移動到前臺或者後臺.假設,例如,當前的任務有四個 activity在棧中——三個在當前的activity之下。用戶按下了HOME鍵,進入了應用程序加載器,選擇了一個新的程序(實際上,是一個新的任務)。當前的任務進入了後臺,新任務的根activity顯示出來。然後,過了一會,用戶退回到主界面,又重新選擇了前一個應用程序(前一個任務),棧中有四個activity的那個任務,現在出現在了前臺。當用戶按下BACK按鍵,屏幕就不會再顯示用戶剛剛離開的那個activity,而是刪除棧頂的 activity,同任務中的前一個activity將被顯示出來。

     剛纔說明的那些行爲,是activity和任務的默認行爲。但是有也辦法修改它的所有方面。activity和任務的關聯,activity在任務中的行爲,受控於啓動activity的行爲對象的標誌位和清單文件中的<activity> 元素的屬性的互相作用。請求者和相應着都要說明發生了什麼。


   在這裏,主要的行爲標誌爲是:



FLAG_ACTIVITY_NEW_TASK 
FLAG_ACTIVITY_CLEAR_TOP 
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED 
FLAG_ACTIVITY_SINGLE_TOP


       主要的<activity> 屬性是:



taskAffinity 
launchMode 
allowTaskReparenting 
clearTaskOnLaunch 
alwaysRetainTaskState 
finishOnTaskLaunch


       下面一節將說明這些標誌和屬性都有什麼用,他們之間怎麼互相影響,應該用什麼樣的方案來控制它們的使用。


親和性和新任務


        默認情況下,應用程序中的所有activity,都有一個對於其它activity的親和性—這是一個對於同一個任務中的其他activity的優先權,然後,通過  <activity>元素的 taskAffinity 屬性可以可以分別爲每一個activity設置親和性。不同應用程序定義的activity可以共享同一個親和性,或者同一個應用程序定義的 activity可以指定不同的親和性。親和性在兩種情況下發揮作用:當行爲對象啓動了一個包含 FLAG_ACTIVITY_NEW_TASK標誌的activity,和當一個activity的allowTaskReparenting 屬性設置爲“true”。


FLAG_ACTIVITY_NEW_TASK  標誌
       

        正如前面描述的,一個新的activity,默認情況下,被加載進調用startActivity()方法的activity對象所在的那個任務中。它被壓入和調用者所在的同一個棧中,但是,如果行爲對象在調用startActivity()方法時傳遞了FLAG_ACTIVITY_NEW_TASK標記,系統將用一個不同的任務來容納這個新的activity。通常,就像這個標記的名字所代表的。它是一個新任務,但是,它不必非要這樣。如果已經存在一個和這個activity親和性相同的任務,這個activity就會載入到那個任務中,如果不是的話,纔會啓動新任務。


allowTaskReparenting  屬性


        如果activity的allowTaskReparenting 屬性設置爲“true”,它就能從他啓動時所在的任務移動到另一個出現在前臺的任務。例如,假設有一個activity可以根據選擇的城市包括天氣情況,它作爲一個旅行應用程序的一部分。它和同一個應用程序中的其他activity有同樣的親和性(默認的親和性)並且允許重組。你的一個activity開啓了天氣報告器,所以它屬於同一個任務中的這個activity,然而,當旅行應用程序開始運行時,天氣報告器將被重新分配並顯示到那個任務中。


啓動模式


        有4中不同的啓動模式可以分配給 <activity> 元素的  launchMode  屬性。


"standard" (默認的模式) 
"singleTop " 
"singleTask" 

"singleInstance"

它們主要有如下不同:

 

1. 如何決定所屬task

“standard”和”singleTop”的activity的目標task,和收到的Intent的發送者在同一個task內,除非intent包括參數FLAG_ACTIVITY_NEW_TASK。

如果提供了FLAG_ACTIVITY_NEW_TASK參數,會啓動到別的task裏。

“singleTask”和”singleInstance”總是把activity作爲一個task的根元素,他們不會被啓動到一個其他task裏。

應該說”singleInstance”總是把activity作爲一個task的根元素,SingleTask就不一定了。


2. 是否允許多個實例

“standard”和”singleTop”可以被實例化多次,並且存在於不同的task中,且一個task可以包括一個activity的多個實例;

“singleTask”和”singleInstance”則限制只生成一個實例,並且是task的根元素。

singleTop要求如果創建intent的時候棧頂已經有要創建 的Activity的實例,則將intent發送給該實例,而不發送給新的實例。

 

3. 是否允許其它activity存在於本task內

“singleInstance”獨佔一個task,其它activity不能存在那個task裏;如果它啓動了一個新的activity,不管新的activity的launch mode 如何,新的activity都將會到別的task裏運行(如同加了FLAG_ACTIVITY_NEW_TASK參數)。

而另外三種模式,則可以和其它activity共存。

 

4. 是否每次都生成新實例

“standard”對於沒一個啓動Intent都會生成一個activity的新實例;

“singleTop”的activity如果在task的棧頂的話,則不生成新的該activity的實例,直接使用棧頂的實例,否則,生成該activity的實例。

比如現在task棧元素爲A-B-C-D(D在棧頂),這時候給D發一個啓動intent,如果D是 “standard”的,則生成D的一個新實例,棧變爲A-B-C-D-D。

如果D是singleTop的話,則不會生產D的新實例,棧狀態仍爲A-B-C-D

如果這時候給B發Intent的話,不管B的launchmode是”standard” 還是 “singleTop” ,都會生成B的新實例,棧狀態變爲A-B-C-D-B。

 

“singleInstance”是其所在棧的唯一activity,它會每次都被重用。

 

“singleTask”如果在棧頂,則接受intent,否則,該intent會被丟棄,但是該task仍會回到前臺。

 

當已經存在的activity實例處理新的intent時候,會調用onNewIntent()方法

如果收到intent生成一個activity實例,那麼用戶可以通過back鍵回到上一個狀態;如果是已經存在的一個activity來處理這個intent的話,用戶不能通過按back鍵返回到這之前的狀態。

總結:

standard  每次都會新建,每個Task都可以有,且每個Task都可以有多個實例(每個Task都可以有,且可以有多個)
singleTop 當前實例如果在棧頂,就不新建實例,調用其OnNewIntent。 如不在棧頂,則新建實例 (每個Task都可以有,且可以有多個,在棧頂時可複用)
singleTask 新建一個Task,如果已經有其他的Task並且包含該實例,那就直接調用那個Task的實例。(只有一個Task中會有)
singleInstance 新建一個Task,且在該Task中只有它的唯一一個實例。 (只有一個Task會有,且該Task中只有它)


FLAG_ACTIVITY_NEW_TASK  類似singleTask
FLAG_ACTIVITY_SINGLE_TOP 類似singleTop 
FLAG_ACTIVITY_CLEAR_TOP 無對應


配兩個圖,我覺得很清晰:

(1)standard  



(2)singleTask


可以將TaskA TaskB理解爲兩個應用,比如TaskA是你當前的應用,TaskB是默認瀏覽器。

當到了TaskB中後,按返回鍵,需要先在TaskB中返回到root,然後才能返回到TaskA。


清理棧




     如果用戶離開一個任務很長時間。系統將清除除了根activity之外的所有activity。當用戶重新回到任務中時,像是用戶離開了它,除了只有最初的activity還在。這個理念是這樣的,過了一段時間,用戶很可能放棄之前所做的事情,回到任務去做一些新的事情。



     這只是默認情況,有一些activity的屬性可以控制和修改它。



alwaysRetainTaskState  屬性


       如果一個任務的根activity的這個屬性設置成了"true",那麼剛纔提到的那些默認行爲就不會發生。這個任務保留所有的activity,甚至經過了很長一段時間。



clearTaskOnLaunch  屬性
       
       如果任務的根activity的這個屬性設置成了”true“,那麼只要用戶離開了任務並返回,就會清除除了根activity之外的所有activity。換句話說,它和alwaysRetainTaskState正好相反,當用戶返回到任務時,總是恢復到最初的狀態,不管離開了多長時間。


finishOnTaskLaunch  屬性


這個屬性和clearTaskOnLaunch類似,但是它作用於單個activity,而不是整個任務。它可以導致任何的activity離開,包括根activity。當它設置成"true"的時候,作爲任務一部分的activity只對當前會話有效。如果用戶離開然後返回到任務中。它將不再出現。


       還有其他的方法強制將activity從棧中移除。如果一個行爲對象包含了 FLAG_ACTIVITY_CLEAR_TOP  標誌,它的目標任務中已經有了一個這樣類型的activity實例,所有棧中位於這個實例之上的activity都會被清除,所以這個實例就會出現在棧頂並且對行爲進行響應。如果activity被設計成"standard"模式,它也將會從棧中被清除,並且會啓動新的實例來處理到來的行爲。這是因爲當設置成”standard“模式後,對每個新的行爲都會創建一個新的實例。


      FLAG_ACTIVITY_CLEAR_TOP經常 和FLAG_ACTIVITY_NEW_TASK一起使用。當一起使用時,這些標誌是定位一個在另一個任務中存在的activity並且將它放在一個可以響應行爲的地方的一種方法。


啓動任務


    Activity通過將行爲過濾器”android .intent.action.MAIN“設置爲指定動作和"android .intent.category.LAUNCHER"作爲指定類型,來成爲任務的入口。(前面關於行爲過濾器那一些討論的例子)。這種類型的過濾器會讓activity的圖標和標籤顯示在應用程序加載器上面,可以讓用戶啓動和返回activity。


    第二個能力更爲重要,用戶應該可以在離開一個任務一段時間後返回。因爲這樣,能夠初始化任務的"singleTask"和"singleInstance"模式,只能夠用在那些擁有MAIN 和LAUNCHER 過濾器的activity中。想像一下如果沒有這兩個過濾器會發生什麼:一個行爲啓動了"singleTask"模式的activity,啓動了一個新的任務並且用戶花了一些時間在這個任務上。然後用戶按下了HOME鍵,這個任務被隱藏到了後臺。因爲沒有在應用程序加載器上顯示它,所以就沒有辦法返回到這個任務。


       一個類似的麻煩事 FLAG_ACTIVITY_NEW_TASK 標誌。如果這個標誌導致activity啓動了一個新任務,並且用戶按下HOME鍵離開了它,必須有一些方法將用戶引導回它。一些實體(像是通知管理器) 總是在一個外部的任務中啓動activity,而不作爲它們的一部分,所以他們總是將帶有FLAG_ACTIVITY_NEW_TASK 標記的行爲對象傳遞到startActivity() 。如果你有一個可以被外部實體使用這個標籤調用的activity,要注意用戶應該有辦法返回到啓動的任務。


    對於那些你不想讓用戶返回到activity的情況,將 <activity>的finishOnTaskLaunch屬性設置爲”true“,參看前面的 清理棧 一節。

發佈了60 篇原創文章 · 獲贊 3 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章