首頁 收藏 QQ群
 網(wǎng)站導(dǎo)航

ZNDS智能電視網(wǎng) 推薦當貝市場

TV應(yīng)用下載 / 資源分享區(qū)

軟件下載 | 游戲 | 討論 | 電視計算器

綜合交流 / 評測 / 活動區(qū)

交流區(qū) | 測硬件 | 網(wǎng)站活動 | Z幣中心

新手入門 / 進階 / 社區(qū)互助

新手 | 你問我答 | 免費刷機救磚 | ROM固件

查看: 12402|回復(fù): 0
上一主題 下一主題
[教程]

Android開發(fā)指南1-框架主題-基礎(chǔ)知識

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2013-8-28 16:28 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
>應(yīng)用程序基礎(chǔ)關(guān)鍵類ActivityServiceBroadcastReceiverContentProviderIntent   
Android應(yīng)用程序使用Java做為開發(fā)語言。[size=1em]aapt工具把編譯后的Java代碼連同其它應(yīng)用程序需要的數(shù)據(jù)和資源文件一起打包到一個Android包文件中,這個文件使用.apk做為擴展名,它是分發(fā)應(yīng)用程序并安裝到移動設(shè)備的媒介,用戶只需下載并安裝此文件到他們的設(shè)備。單一.apk文件中的所有代碼被認為是一個應(yīng)用程序。
從很多方面來看,每個Android應(yīng)用程序都存在于它自己的世界之中:
默認情況下,每個應(yīng)用程序均運行于它自己的Linux進程中。當應(yīng)用程序中的任意代碼開始執(zhí)行時,Android啟動一個進程,而當不再需要此進程而其它應(yīng)用程序又需要系統(tǒng)資源時,則關(guān)閉這個進程。每個進程都運行于自己的Java虛擬機(VM)中。所以應(yīng)用程序代碼實際上與其它應(yīng)用程序的代碼是隔絕的。默認情況下,每個應(yīng)用程序均被賦予一個唯一的Linux用戶ID,并加以權(quán)限設(shè)置,使得應(yīng)用程序的文件僅對這個用戶、這個應(yīng)用程序可見。當然,也有其它的方法使得這些文件同樣能為別的應(yīng)用程序所訪問。   
使兩個應(yīng)用程序共有同一個用戶ID是可行的,這種情況下他們可以看到彼此的文件。從系統(tǒng)資源維護的角度來看,擁有同一個ID的應(yīng)用程序也將在運行時使用同一個Linux進程,以及同一個虛擬機。
應(yīng)用程序組件
Android的核心功能之一就是一個應(yīng)用程序可以使用其它應(yīng)用程序的元素(如果那個應(yīng)用程序允許的話)。比如說,如果你的應(yīng)用程序需要一個圖片卷動列表,而另一個應(yīng)用程序已經(jīng)開發(fā)了一個合用的而又允許別人使用的話,你可以直接調(diào)用那個卷動列表來完成工作,而不用自己再開發(fā)一個。你的應(yīng)用程序并沒有吸納或鏈接其它應(yīng)用程序的代碼,它只是在有需求的時候啟動了其它應(yīng)用程序的那個功能部分。
為達到這個目的,系統(tǒng)必須在一個應(yīng)用程序的一部分被需要時啟動這個應(yīng)用程序,并將那個部分的Java對象實例化。與在其它系統(tǒng)上的應(yīng)用程序不同,Android應(yīng)用程序沒有為應(yīng)用準備一個單獨的程序入口(比如說,沒有[size=1em]main()方法), 而是為系統(tǒng)依照需求實例化提供了基本的組件。共有四種組件類型:
Activity是為用戶操作而展示的可視化用戶界面。比如說,一個activity可以展示一個菜單項列表供用戶選擇,或者顯示一些包含說明的照片。一個短消息應(yīng)用程序可以包括一個用于顯示做為發(fā)送對象的聯(lián)系人的列表的activity,一個給選定的聯(lián)系人寫短信的activity以及翻閱以前的短信和改變設(shè)置的activity。盡管它們一起組成了一個內(nèi)聚的用戶界面,但其中每個activity都與其它的保持獨立。每個都是以Activity類為基類的子類實現(xiàn)。
一個應(yīng)用程序可以只有一個activity,或者,如剛才提到的短信應(yīng)用程序那樣,包含很多個。每個activity的作用,以及其數(shù)目,自然取決于應(yīng)用程序及其設(shè)計。一般情況下,總有一個應(yīng)用程序被標記為用戶在應(yīng)用程序啟動的時候第一個看到的。從一個activity轉(zhuǎn)向另一個的方式是靠當前的activity啟動下一個。
每個activity都被給予一個默認的窗口以進行繪制。一般情況下,這個窗口是滿屏的,但它也可以是一個小的位于其它窗口之上的浮動窗口。一個activity也可以使用超過一個的窗口──比如,在activity運行過程中彈出的一個供用戶反應(yīng)的小對話框,或是當用戶選擇了屏幕上特定項目后顯示的必要信息。
窗口顯示的可視內(nèi)容是由一系列視圖構(gòu)成的,這些視圖均繼承自 View 基類。每個視圖均控制著窗口中一塊特定的矩形空間。父級視圖包含并組織它子視圖的布局。葉節(jié)點視圖(位于視圖層次最底端)在它們控制的矩形中進行繪制,并對用戶對其直接操作做出響應(yīng)。所以,視圖是activity與用戶進行交互的界面。比如說,視圖可以顯示一個小圖片,并在用戶指點它的時候產(chǎn)生動作。Android有很多既定的視圖供用戶直接使用,包括按鈕、文本域、卷軸、菜單項、復(fù)選框等等。
視圖層次是由Activity.setContentView() 方法放入activity的窗口之中的。上下文視圖是位于視圖層次根位置的視圖對象。(參見用戶界面章節(jié)獲取關(guān)于視圖及層次的更多信息。)
服務(wù)沒有可視化的用戶界面,而是在一段時間內(nèi)在后臺運行。比如說,一個服務(wù)可以在用戶做其它事情的時候在后臺播放背景音樂、從網(wǎng)絡(luò)上獲取一些數(shù)據(jù)或者計算一些東西并提供給需要這個運算結(jié)果的activity使用。每個服務(wù)都繼承自Service基類。
一個媒體播放器播放播放列表中的曲目是一個不錯的例子。播放器應(yīng)用程序可能有一個或多個activity來給用戶選擇歌曲并進行播放。然而,音樂播放這個任務(wù)本身不應(yīng)該為任何activity所處理,因為用戶期望在他們離開播放器應(yīng)用程序而開始做別的事情時,音樂仍在繼續(xù)播放。為達到這個目的,媒體播放器activity應(yīng)該啟用一個運行于后臺的服務(wù)。而系統(tǒng)將在這個activity不再顯示于屏幕之后,仍維持音樂播放服務(wù)的運行。
你可以連接至(綁定)一個正在運行的服務(wù)(如果服務(wù)沒有運行,則啟動之)。連接之后,你可以通過那個服務(wù)暴露出來的接口與服務(wù)進行通訊。對于音樂服務(wù)來說,這個接口可以允許用戶暫停、回退、停止以及重新開始播放。
如同activity和其它組件一樣,服務(wù)運行于應(yīng)用程序進程的主線程內(nèi)。所以它不會對其它組件或用戶界面有任何干擾,它們一般會派生一個新線程來進行一些耗時任務(wù)(比如音樂回放)。參見下述 進程和線程 。
廣播接收器是一個專注于接收廣播通知信息,并做出對應(yīng)處理的組件。很多廣播是源自于系統(tǒng)代碼的──比如,通知時區(qū)改變、電池電量低、拍攝了一張照片或者用戶改變了語言選項。應(yīng)用程序也可以進行廣播──比如說,通知其它應(yīng)用程序一些數(shù)據(jù)下載完成并處于可用狀態(tài)。
   
應(yīng)用程序可以擁有任意數(shù)量的廣播接收器以對所有它感興趣的通知信息予以響應(yīng)。所有的接收器均繼承自BroadcastReceiver基類。   
廣播接收器沒有用戶界面。然而,它們可以啟動一個activity來響應(yīng)它們收到的信息,或者用NotificationManager來通知用戶。通知可以用很多種方式來吸引用戶的注意力──閃動背燈、震動、播放聲音等等。一般來說是在狀態(tài)欄上放一個持久的圖標,用戶可以打開它并獲取消息。
內(nèi)容提供者將一些特定的應(yīng)用程序數(shù)據(jù)供給其它應(yīng)用程序使用。數(shù)據(jù)可以存儲于文件系統(tǒng)、SQLite數(shù)據(jù)庫或其它方式。內(nèi)容提供者繼承于ContentProvider 基類,為其它應(yīng)用程序取用和存儲它管理的數(shù)據(jù)實現(xiàn)了一套標準方法。然而,應(yīng)用程序并不直接調(diào)用這些方法,而是使用一個 ContentResolver 對象,調(diào)用它的方法作為替代。ContentResolver可以與任意內(nèi)容提供者進行會話,與其合作來對所有相關(guān)交互通訊進行管理。
參閱獨立的內(nèi)容提供者章節(jié)獲得更多關(guān)于使用內(nèi)容提供者的內(nèi)容。
每當出現(xiàn)一個需要被特定組件處理的請求時,Android會確保那個組件的應(yīng)用程序進程處于運行狀態(tài),或在必要的時候啟動它。并確保那個相應(yīng)組件的實例的存在,必要時會創(chuàng)建那個實例。
激活組件:intent
當接收到ContentResolver發(fā)出的請求后,內(nèi)容提供者被激活。而其它三種組件──activity、服務(wù)和廣播接收器被一種叫做intent的異步消息所激活。intent是一個保存著消息內(nèi)容的Intent對象。對于activity和服務(wù)來說,它指明了請求的操作名稱以及作為操作對象的數(shù)據(jù)的URI和其它一些信息。比如說,它可以承載對一個activity的請求,讓它為用戶顯示一張圖片,或者讓用戶編輯一些文本。而對于廣播接收器而言,Intent對象指明了聲明的行為。比如,它可以對所有感興趣的對象聲明照相按鈕被按下。
對于每種組件來說,激活的方法是不同的:
通過傳遞一個Intent對象至 Context.startActivity()或Activity.startActivityForResult()以載入(或指定新工作給)一個activity。相應(yīng)的activity可以通過調(diào)用 getIntent() 方法來查看激活它的intent。Android通過調(diào)用activity的onNewIntent()方法來傳遞給它繼發(fā)的intent。   
一個activity經(jīng)常啟動了下一個。如果它期望它所啟動的那個activity返回一個結(jié)果,它會以調(diào)用[size=1em]startActivityForResult()來取代startActivity()。比如說,如果它啟動了另外一個activity以使用戶挑選一張照片,它也許想知道哪張照片被選中了。結(jié)果將會被封裝在一個Intent對象中,并傳遞給發(fā)出調(diào)用的activity的onActivityResult() 方法。通過傳遞一個Intent對象至Context.startService()將啟動一個服務(wù)(或給予正在運行的服務(wù)以一個新的指令)。Android調(diào)用服務(wù)的 onStart()方法并將Intent對象傳遞給它。   
與此類似,一個Intent可以被調(diào)用組件傳遞給 Context.bindService()以獲取一個正在運行的目標服務(wù)的連接。這個服務(wù)會經(jīng)由onBind() 方法的調(diào)用獲取這個Intent對象(如果服務(wù)尚未啟動,[size=1em]bindService()會先啟動它)。比如說,一個activity可以連接至前述的音樂回放服務(wù),并提供給用戶一個可操作的(用戶界面)以對回放進行控制。這個activity可以調(diào)用 [size=1em]bindService() 來建立連接,然后調(diào)用服務(wù)中定義的對象來影響回放。   
后面一節(jié):遠程方法調(diào)用將更詳細的闡明如何綁定至服務(wù)。應(yīng)用程序可以憑借將Intent對象傳遞給 Context.sendBroadcast() ,Context.sendOrderedBroadcast(), 以及Context.sendStickyBroadcast()和其它類似方法來產(chǎn)生一個廣播。Android會調(diào)用所有對此廣播有興趣的廣播接收器的 onReceive()方法,將intent傳遞給它們。   
欲了解更多intent消息的信息,請參閱獨立章節(jié) Intent和Intent濾過器。
關(guān)閉組件
內(nèi)容提供者僅在響應(yīng)ContentResolver提出請求的時候激活。而一個廣播接收器僅在響應(yīng)廣播信息的時候激活。所以,沒有必要去顯式的關(guān)閉這些組件。
而activity則不同,它提供了用戶界面,并與用戶進行會話。所以只要會話依然持續(xù),哪怕對話過程暫時停頓,它都會一直保持激活狀態(tài)。與此相似,服務(wù)也會在很長一段時間內(nèi)保持運行。所以Android為關(guān)閉activity和服務(wù)提供了一系列的方法。
可以通過調(diào)用它的finish()方法來關(guān)閉一個activity。一個activity可以通過調(diào)用另外一個activity(它用[size=1em]startActivityForResult() 啟動的)的finishActivity()方法來關(guān)閉它。服務(wù)可以通過調(diào)用它的stopSelf()方法來停止,或者調(diào)用 Context.stopService()。   
系統(tǒng)也會在組件不再被使用的時候或者Android需要為活動組件聲明更多內(nèi)存的時候關(guān)閉它。后面的 組件的生命周期一節(jié),將對這種可能及附屬情況進行更詳細的討論。
manifest文件
當Android啟動一個應(yīng)用程序組件之前,它必須知道那個組件是存在的。所以,應(yīng)用程序會在一個manifest文件中聲明它的組件,這個文件會被打包到Android包中。這個.apk文件還將涵括應(yīng)用程序的代碼、文件以及其它資源。
這個manifest文件以XML作為結(jié)構(gòu)格式,而且對于所有應(yīng)用程序,都叫做AndroidManifest.xml。為聲明一個應(yīng)用程序組件,它還會做很多額外工作,比如指明應(yīng)用程序所需鏈接到的庫的名稱(除了默認的Android庫之外)以及聲明應(yīng)用程序期望獲得的各種權(quán)限。
但manifest文件的主要功能仍然是向Android聲明應(yīng)用程序的組件。舉例說明,一個activity可以如下聲明:
   
  1. <?xml version="1.0" encoding="utf-8"?>   
    <manifest . . . >   
        <application . . . >   
            <activity android:name="com.example.project.FreneticActivity"   
                      android:icon="@drawable/small_pic.png"   
                      android:label="@string/freneticLabel"   
                      . . .  >   
            </activity>   
            . . .   
        </application>   
    </manifest>
復(fù)制代碼
  
<activity>元素的name屬性指定了實現(xiàn)了這個activity的 Activity的子類。icon和label屬性指向了包含展示給用戶的此activity的圖標和標簽的資源文件。
其它組件也以類似的方法聲明──<service> 元素用于聲明服務(wù), <receiver> 元素用于聲明廣播接收器,而 <provider> 元素用于聲明內(nèi)容提供者。 manifest文件中未進行聲明的activity、服務(wù)以及內(nèi)容提供者將不為系統(tǒng)所見,從而也就不會被運行。然而,廣播接收器既可以在manifest文件中聲明,也可以在代碼中進行動態(tài)的創(chuàng)建,并以調(diào)用Context.registerReceiver()的方式注冊至系統(tǒng)。
欲更多了解如何為你的應(yīng)用程序構(gòu)建manifest文件,請參閱AndroidManifest.xml文件一章。
Intent過濾器
Intent對象可以被顯式的指定目標組件。如果進行了這種指定,Android會找到這個組件(依據(jù)manifest文件中的聲明)并激活它。但如果Intent沒有進行顯式的指定,Android就必須為它找到對于intent來說最合適的組件。這個過程是通過比較Intent對象和所有可能對象的intent過濾器完成的。組件的intent過濾器會告知Android它所能處理的intent類型。如同其它相對于組件很重要的信息一樣,這些是在manifest文件中進行聲明的。這里是上面實例的一個擴展,其中加入了針對activity的兩個intent過濾器聲明:
   
  1. <?xml version="1.0" encoding="utf-8"?>   
    <manifest . . . >   
        <application . . . >   
            <activity android:name="com.example.project.FreneticActivity"   
                      android:icon="@drawable/small_pic.png"   
                      android:label="@string/freneticLabel"   
                      . . .  >   
                <intent-filter . . . >   
                    <action android:name="android.intent.action.MAIN" />   
                    <category android:name="android.intent.category.LAUNCHER" />   
                </intent-filter>   
                <intent-filter . . . >   
                    <action android:name="com.example.project.BOUNCE" />   
                    <data android:type="image/jpeg" />   
                    <category android:name="android.intent.category.DEFAULT" />   
                </intent-filter>   
            </activity>   
            . . .   
        </application>   
    </manifest>
復(fù)制代碼
  
示例中的第一個過濾器──action “[size=1em]android.intent.action.MAIN”和類別“[size=1em]android.intent.category.LAUNCHER”的組合──是通常具有的。它標明了這個activity將在應(yīng)用程序加載器中顯示,就是用戶在設(shè)備上看到的可供加載的應(yīng)用程序列表。換句話說,這個activity是應(yīng)用程序的入口,是用戶選擇運行這個應(yīng)用程序后所見到的第一個activity。
第二個過濾器聲明了這個activity能被賦予一種特定類型的數(shù)據(jù)。
組件可以擁有任意數(shù)量的intent過濾器,每個都會聲明一系列不同的能力。如果它沒有包含任何過濾器,它將只能被顯式聲明了目標組件名稱的intent激活。
對于在代碼中創(chuàng)建并注冊的廣播接收器來說,intent過濾器將被直接以 IntentFilter對象實例化。其它過濾器則在manifest文件中設(shè)置。
欲獲得更多intent過濾器的信息,請參閱獨立章節(jié): Intent和Intent過濾器。
Activity和任務(wù)
如前所述,一個activity可以啟動另外一個,甚至包括與它不處于同一應(yīng)用程序之中的。舉個例子說,假設(shè)你想讓用戶看到某個地方的街道地圖。而已經(jīng)存在一個具有此功能的activity了,那么你的activity所需要做的工作就是把請求信息放到一個Intent對象里面,并把它傳遞給[size=1em]startActivity()。于是地圖瀏覽器就會顯示那個地圖。而當用戶按下BACK鍵的時候,你的activity又會再一次的顯示在屏幕上。
對于用戶來說,這看起來就像是地圖瀏覽器是你activity所在的應(yīng)用程序中的一個組成部分,其實它是在另外一個應(yīng)用程序中定義,并運行在那個應(yīng)用程序的進程之中的。Android將這兩個activity放在同一個任務(wù)中來維持一個完整的用戶體驗。簡單的說,任務(wù)就是用戶所體驗到的“應(yīng)用程序”。它是安排在一個堆棧中的一組相關(guān)的activity。堆棧中的根activity就是啟動了這整個任務(wù)的那個──一般情況下,它就是用戶在應(yīng)用程序加載器中所選擇的。而堆棧最上方的activity則是當前運行的──用戶直接對其進行操作的。當一個activity啟動另外一個的時候,新的activity就被壓入堆棧,并成為當前運行的activity。而前一個activity仍保持在堆棧之中。當用戶按下BACK鍵的時候,當前activity出棧,而前一個恢復(fù)為當前運行的activity。
堆棧中保存的其實是對象,所以如果發(fā)生了諸如需要多個地圖瀏覽器的情況,就會使得一個任務(wù)中出現(xiàn)多個同一Activity子類的實例同時存在,堆棧會為每個實例單獨開辟一個入口。堆棧中的Activity永遠不會重排,只會壓入或彈出。
任務(wù)其實就是activity的堆棧,而不是manifest文件中的一個類或者元素。所以你無法撇開activity而為一個任務(wù)設(shè)置一個值。而事實上整個任務(wù)使用的值是在根activity中設(shè)置的。比如說,下一節(jié)我們會談及“任務(wù)的affinity”,從affinity中讀出的值將會設(shè)置到任務(wù)的根activity之中。
任務(wù)中的所有activity是作為一個整體進行移動的。整個的任務(wù)(即activity堆棧)可以移到前臺,或退至后臺。舉個例子說,比如當前任務(wù)在堆棧中存有四個activity──三個在當前activity之下。當用戶按下HOME鍵的時候,回到了應(yīng)用程序加載器,然后選擇了一個新的應(yīng)用程序(也就是一個新任務(wù))。則當前任務(wù)遁入后臺,而新任務(wù)的根activity顯示出來。然后,過了一小會兒,用戶再次回到了應(yīng)用程序加載器而又選擇了前一個應(yīng)用程序(上一個任務(wù))。于是那個任務(wù),帶著它堆棧中所有的四個activity,再一次的到了前臺。當用戶按下BACK鍵的時候,屏幕不會顯示出用戶剛才離開的activity(上一個任務(wù)的根activity)。取而代之,當前任務(wù)的堆棧中最上面的activity被彈出,而同一任務(wù)中的上一個activity顯示了出來。
上述的種種即是activity和任務(wù)的默認行為模式。但是有一些方法可以改變所有這一切。activity和任務(wù)的聯(lián)系、任務(wù)中activity的行為方式都被啟動那個activity的Intent對象中設(shè)置的一系列標記和manifest文件中那個activity中的<activity>元素的系列屬性之間的交互所控制。無論是請求發(fā)出者和回應(yīng)者在這里都擁有話語權(quán)。
我們剛才所說的這些關(guān)鍵Intent標記如下:
[size=1em]FLAG_ACTIVITY_NEW_TASK   
[size=1em]FLAG_ACTIVITY_CLEAR_TOP   
[size=1em]FLAG_ACTIVITY_RESET_TASK_IF_NEEDED   
[size=1em]FLAG_ACTIVITY_SINGLE_TOP
而關(guān)鍵的[size=1em]<activity>屬性是:
[size=1em]taskAffinity   
[size=1em]launchMode   
[size=1em]allowTaskReparenting   
[size=1em]clearTaskOnLaunch   
[size=1em]alwaysRetainTaskState   
[size=1em]finishOnTaskLaunch
接下來的一節(jié)會描述這些標記以及屬性的作用,它們是如何互相影響的,以及控制它們的使用時必須考慮到的因素。
Affinity(吸引力)和新任務(wù)
默認情況下,一個應(yīng)用程序中的activity相互之間會有一種Affinity──也就是說,它們首選都歸屬于一個任務(wù)。然而,可以在[size=1em]<activity>元素中把每個activity的taskAffinity屬性設(shè)置為一個獨立的affinity。于是在不同的應(yīng)用程序中定義的activity可以享有同一個affinity,或者在同一個應(yīng)用程序中定義的activity有著不同的affinity。affinity在兩種情況下生效:當加載activity的Intent對象包含了[size=1em]FLAG_ACTIVITY_NEW_TASK 標記,或者當activity的[size=1em]allowTaskReparenting屬性設(shè)置為“true”。
FLAG_ACTIVITY_NEW_TASK標記
如前所述,在默認情況下,一個新activity被另外一個調(diào)用了[size=1em]startActivity()方法的activity載入了任務(wù)之中。并壓入了調(diào)用者所在的堆棧。然而,如果傳遞給[size=1em]startActivity()的Intent對象包含了[size=1em]FLAG_ACTIVITY_NEW_TASK標記,系統(tǒng)會為新activity安排另外一個任務(wù)。一般情況下,如同標記所暗示的那樣,這會是一個新任務(wù)。然而,這并不是必然的。如果已經(jīng)存在了一個與新activity有著同樣affinity的任務(wù),則activity會載入那個任務(wù)之中。如果沒有,則啟用新任務(wù)。
allowTaskReparenting 屬性
如果一個activity將[size=1em]allowTaskReparenting屬性設(shè)置為“true”。它就可以從初始的任務(wù)中轉(zhuǎn)移到與其擁有同一個affinity并轉(zhuǎn)向前臺的任務(wù)之中。比如說,一個旅行應(yīng)用程序中包含的預(yù)報所選城市的天氣情況的activity。它與這個應(yīng)用程序中其它的activity擁有同樣的affinity(默認的affinity)而且允許重定父級。你的另一個activity啟動了天氣預(yù)報,于是它就會與這個activity共處與同一任務(wù)之中。然而,當那個旅行應(yīng)用程序再次回到前臺的時候,這個天氣預(yù)報activity就會被再次安排到原先的任務(wù)之中并顯示出來。
如果在用戶的角度看來,一個.apk文件中包含了多于一個的“應(yīng)用程序”,你可能會想要為它們所轄的activity安排不一樣的affinity。
加載模式
[size=1em]<activity>元素的launchMode屬性可以設(shè)置四種不同的加載模式:
"[size=1em]standard" (默認值)   
"[size=1em]singleTop"   
"[size=1em]singleTask"   
"[size=1em]singleInstance"
這些模式之間的差異主要體現(xiàn)在四個方面:
對“[size=1em]standard”和“[size=1em]singleTop”模式而言,是產(chǎn)生intent(并調(diào)用 startActivity())的任務(wù)──除非Intent對象包含F(xiàn)LAG_ACTIVITY_NEW_TASK標記。而在這種情況下,如同上面Affinitie和新任務(wù)一節(jié)所述,會是另外一個任務(wù)。
相反,對“[size=1em]singleTask”和“[size=1em]singleInstance”模式而言,activity總是位于任務(wù)的根部。正是它們定義了一個任務(wù),所以它們絕不會被載入到其它任務(wù)之中。
一個“[size=1em]standard”或“[size=1em]singleTop”的activity可以被多次初始化。它們可以歸屬于多個任務(wù),而一個任務(wù)也可以擁有同一activity的多個實例。
相反,對“[size=1em]singleTask”和“[size=1em]singleInstance”的activity被限定于只能有一個實例。因為這些activity都是任務(wù)的起源,這種限制意味著在一個設(shè)備中同一時間只允許存在一個任務(wù)的實例。
一個“[size=1em]singleInstance”模式的activity將會是它所在的任務(wù)中唯一的activity。如果它啟動了別的activity,那個activity將會依據(jù)它自己的加載模式加載到其它的任務(wù)中去──如同在intent中設(shè)置了[size=1em]FLAG_ACTIVITY_NEW_TASK 標記一樣的效果。在其它方面,“[size=1em]singleInstance”模式的效果與“[size=1em]singleTask”是一樣的。
剩下的三種模式允許一個任務(wù)中出現(xiàn)多個activity?!癧size=1em]singleTask”模式的activity將是任務(wù)的根activity,但它可以啟動別的activity并將它們置入所在的任務(wù)中。“[size=1em]standard”和“[size=1em]singleTop”activity則可以在堆棧的任意位置出現(xiàn)。
   
對默認的"[size=1em]standard"模式來說,對于每個新intent都會創(chuàng)建一個新的實例以進行響應(yīng),每個實例僅處理一個intent?!癧size=1em]singleTop”模式下,如果activity位于目的任務(wù)堆棧的最上面,則重用目前現(xiàn)存的activity來處理新的intent。如果它不是在堆棧頂部,則不會發(fā)生重用。而是創(chuàng)建一個新實例來處理新的intent并將其推入堆棧。
舉例來說,假設(shè)一個任務(wù)的堆棧由根activityA和activity B、C和位于堆棧頂部的D組成,即堆棧A-B-C-D。一個針對D類型的activity的intent抵達的時候,如果D是默認的“[size=1em]standard”加載模式,則創(chuàng)建并加載一個新的類實例,于是堆棧變?yōu)锳-B-C-D-D。 然而,如果D的載入模式為“[size=1em]singleTop”,則現(xiàn)有的實例會對新intent進行處理(因為它位于堆棧頂部)而堆棧保持A-B-C-D的形態(tài)。
換言之,如果新抵達的intent是針對B類型的activity,則無論B的模式是“[size=1em]standard”還是“[size=1em]singleTop” ,都會加載一個新的B的實例(因為B不位于堆棧的頂部),而堆棧的順序變?yōu)锳-B-C-D-B。
如前所述,“[size=1em]singleTask”或“[size=1em]singleInstance”模式的activity永遠不會存在多于一個實例。所以實例將處理所有新的intent。一個“[size=1em]singleInstance”模式的activity永遠保持在堆棧的頂部(因為它是那個堆棧中唯一的一個activity),所以它一直堅守在處理intent的崗位上。然而,對一個“[size=1em]singleTask”模式的activity來說,它上面可能有,也可能沒有別的activity和它處于同一堆棧。[size=1em]在有的情況下,它就不在能夠處理intent的位置上,則那個intent將被舍棄。(即便在intent被舍棄的情況下,它的抵達仍將使這個任務(wù)切換至前臺,并一直保留)
   
當一個現(xiàn)存的activity被要求處理一個新的intent的時候,會調(diào)用onNewIntent()方法來將intent對象傳遞至activity。(啟動activity的原始intent對象可以通過調(diào)用getIntent()方法獲得。)
請注意,當一個新的activity實例被創(chuàng)建以處理新的intent的時候,用戶總可以按下BACK鍵來回到前面的狀態(tài)(回到前一個activity)。但當使用現(xiàn)存的activity來處理新intent的時候,用戶是不能靠按下BACK鍵回到當這個新intent抵達之前的狀態(tài)的。
想獲得更多關(guān)于加載模式的內(nèi)容,請參閱 <activity> 元素的描述。
清理堆棧
如果用戶離開一個任務(wù)很長一段時間,系統(tǒng)會清理該任務(wù)中除了根activity之外的所有activity。當用戶再次回到這個任務(wù)的時候,除了只剩下初始化activity尚存之外,其余都跟用戶上次離開它的時候一樣。這樣做的原因是:在一段時間之后,用戶再次回到一個任務(wù)的時候,他們更期望放棄他們之前的所作所為,做些新的事情。
這些屬于默認行為,另外,也存在一些activity的屬性用以控制并改變這些行為:
alwaysRetainTaskState 屬性
如果一個任務(wù)的根activity中此屬性設(shè)置為“[size=1em]true”,則上述默認行為不會發(fā)生。任務(wù)將在很長的一段時間內(nèi)保留它堆棧內(nèi)的所有activity。
clearTaskOnLaunch屬性
如果一個任務(wù)的根activity中此屬性設(shè)置為“[size=1em]true”,則每當用戶離開這個任務(wù)和返回它的時候,堆棧都會被清空至只留下rootactivity。換句話說,這是[size=1em]alwaysRetainTaskState的另一個極端。哪怕僅是過了一小會兒,用戶回到任務(wù)時,也是見到它的初始狀態(tài)。
finishOnTaskLaunch屬性
這個屬性與[size=1em]clearTaskOnLaunch屬性相似,但它僅作用于單個的activity,而不是整個的task。而且它可以使任意activity都被清理,甚至根activity也不例外。當它設(shè)置為“[size=1em]true”的時候,此activity僅做為任務(wù)的一部分存在于當前回話中,一旦用戶離開并再次回到這個任務(wù),此activity將不復(fù)存在。
此外,還有別的方式從堆棧中移除一個activity。如果一個intent對象包含F(xiàn)LAG_ACTIVITY_CLEAR_TOP標記,而且目標任務(wù)的堆棧中已經(jīng)存在了一個能夠響應(yīng)此intent的activity類型的實例。則這個實例之上的所有activity都將被清理以使它位于堆棧的頂部來對intent做出響應(yīng)。如果此時指定的activity的加載模式為“[size=1em]standard”,則它本身也會從堆棧中移除,并加載一個新的實例來處理到來的intent。這是因為加載模式為“[size=1em]standard”的activity總會創(chuàng)建一個新實例來處理新的intent。
   

上一篇:《Android Dev Guide》系列教程1:什么是Android?
下一篇:EditText的一些使用注意點
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

Archiver|新帖|標簽|軟件|Sitemap|ZNDS智能電視網(wǎng) ( 蘇ICP備2023012627號 )

網(wǎng)絡(luò)信息服務(wù)信用承諾書 | 增值電信業(yè)務(wù)經(jīng)營許可證:蘇B2-20221768 丨 蘇公網(wǎng)安備 32011402011373號

GMT+8, 2024-10-23 06:17 , Processed in 0.080528 second(s), 15 queries , Redis On.

Powered by Discuz!

監(jiān)督舉報:report#znds.com (請將#替換為@)

© 2007-2024 ZNDS.Com

快速回復(fù) 返回頂部 返回列表