日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Application Fundamentals

發(fā)布時(shí)間:2023/12/4 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Application Fundamentals 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Application Fundamentals

署名:譯言biAji

鏈接:http://developer.android.com/guide/topics/fundamentals.html?

?

應(yīng)用程序基礎(chǔ)(Application Fundamentals)

Android應(yīng)用程序使用Java做為開發(fā)語言。aapt工具把編譯后的Java代碼連同其它應(yīng)用程序需要的數(shù)據(jù)和資源文件一起打包到一個(gè)Android包文件中,這個(gè)文件使用.apk做為擴(kuò)展名,它是分發(fā)應(yīng)用程序并安裝到移動(dòng)設(shè)備的媒介,用戶只需下載并安裝此文件到他們的設(shè)備。單一.apk文件中的所有代碼被認(rèn)為是一個(gè)應(yīng)用程序。

從很多方面來看,每個(gè)Android應(yīng)用程序都存在于它自己的世界之中:

l 默認(rèn)情況下,每個(gè)應(yīng)用程序均運(yùn)行于它自己的Linux進(jìn)程中。當(dāng)應(yīng)用程序中的任意代碼開始執(zhí)行時(shí),Android啟動(dòng)一個(gè)進(jìn)程,而當(dāng)不再需要此進(jìn)程而其它應(yīng)用程序又需要系統(tǒng)資源時(shí),則關(guān)閉這個(gè)進(jìn)程。

l 每個(gè)進(jìn)程都運(yùn)行于自己的Java虛擬機(jī)(VM)中。所以應(yīng)用程序代碼實(shí)際上與其它應(yīng)用程序的代碼是隔絕的。

l 默認(rèn)情況下,每個(gè)應(yīng)用程序均被賦予一個(gè)唯一的Linux用戶ID,并加以權(quán)限設(shè)置,使得應(yīng)用程序的文件僅對這個(gè)用戶、這個(gè)應(yīng)用程序可見。當(dāng)然,也有其它的方法使得這些文件同樣能為別的應(yīng)用程序所訪問。

使兩個(gè)應(yīng)用程序共有同一個(gè)用戶ID是可行的,這種情況下他們可以看到彼此的文件。從系統(tǒng)資源維護(hù)的角度來看,擁有同一個(gè)ID的應(yīng)用程序也將在運(yùn)行時(shí)使用同一個(gè)Linux進(jìn)程,以及同一個(gè)虛擬機(jī)。

?

應(yīng)用程序組件(Application Components)

?????? Android的核心功能之一就是一個(gè)應(yīng)用程序可以使用其它應(yīng)用程序的元素(如果那個(gè)應(yīng)用程序允許的話)。比如說,如果你的應(yīng)用程序需要一個(gè)圖片卷動(dòng)列 表,而另一個(gè)應(yīng)用程序已經(jīng)開發(fā)了一個(gè)合用的而又允許別人使用的話,你可以直接調(diào)用那個(gè)卷動(dòng)列表來完成工作,而不用自己再開發(fā)一個(gè)。你的應(yīng)用程序并沒有吸納 或鏈接其它應(yīng)用程序的代碼,它只是在有需求的時(shí)候啟動(dòng)了其它應(yīng)用程序的那個(gè)功能部分。

???????? 為達(dá)到這個(gè)目的,系統(tǒng)必須在一個(gè)應(yīng)用程序的一部分被需要時(shí)啟動(dòng)這個(gè)應(yīng)用程序,并將那個(gè)部分的Java對象實(shí)例化。與在其它系統(tǒng)上的應(yīng)用程序不同,Android應(yīng)用程序沒有為應(yīng)用準(zhǔn)備一個(gè)單獨(dú)的程序入口(比如說,沒有main()方法), 而是為系統(tǒng)依照需求實(shí)例化提供了基本的組件。共有四種組件類型:

?????????Activities

l? Activity是為用戶操作而展示的可視化用戶界面。比如說,一個(gè)activity可以展示一個(gè)菜單項(xiàng)列表供用戶選擇,或者顯示一些包含說明的照片。一個(gè)短消息應(yīng)用程序可以包括一個(gè)用于顯示做為發(fā)送對象的聯(lián)系人的列表的activity,一個(gè)給選定的聯(lián)系人寫短信的activity以及翻閱以前的短信和改變設(shè)置的activity。盡管它們一起組成了一個(gè)內(nèi)聚的用戶界面,但其中每個(gè)activity都與其它的保持獨(dú)立。每個(gè)都是以Activity類為基類的子類實(shí)現(xiàn)。

l? 一個(gè)應(yīng)用程序可以只有一個(gè)activity,或者,如剛才提到的短信應(yīng)用程序那樣,包含很多個(gè)。每個(gè)activity的作用,以及其數(shù)目,自然取決于應(yīng)用 程序及其設(shè)計(jì)。一般情況下,總有一個(gè)應(yīng)用程序被標(biāo)記為用戶在應(yīng)用程序啟動(dòng)的時(shí)候第一個(gè)看到的。從一個(gè)activity轉(zhuǎn)向另一個(gè)的方式是靠當(dāng)前的 activity啟動(dòng)下一個(gè)。

l? 每個(gè)activity都被給予一個(gè)默認(rèn)的窗口以進(jìn)行繪制。一般情況下,這個(gè)窗口是滿屏的,但它也可以是一個(gè)小的位于其它窗口之上的浮動(dòng)窗口。一個(gè) activity也可以使用超過一個(gè)的窗口──比如,在activity運(yùn)行過程中彈出的一個(gè)供用戶反應(yīng)的小對話框,或是當(dāng)用戶選擇了屏幕上特定項(xiàng)目后顯 示的必要信息。

l? 窗口顯示的可視內(nèi)容是由一系列視圖構(gòu)成的,這些視圖均繼承自?View?基類。每個(gè)視圖均控制著窗口中一塊特定的矩形空 間。父級視圖包含并組織它子視圖的布局。葉節(jié)點(diǎn)視圖(位于視圖層次最底端)在它們控制的矩形中進(jìn)行繪制,并對用戶對其直接操作做出響應(yīng)。所以,視圖是 activity與用戶進(jìn)行交互的界面。比如說,視圖可以顯示一個(gè)小圖片,并在用戶指點(diǎn)它的時(shí)候產(chǎn)生動(dòng)作。Android有很多既定的視圖供用戶直接使 用,包括按鈕、文本域、卷軸、菜單項(xiàng)、復(fù)選框等等。

l? 視圖層次是由Activity.setContentView()?方法放入activity的窗口之中的。上下文視圖是位于視圖層次根位置的視圖對象。(參見用戶界面章節(jié)獲取關(guān)于視圖及層次的更多信息。)

?????????服務(wù)(Services)

l? 服務(wù)沒有可視化的用戶界面,而是在一段時(shí)間內(nèi)在后臺(tái)運(yùn)行。比如說,一個(gè)服務(wù)可以在用戶做其它事情的時(shí)候在后臺(tái)播放背景音樂、從網(wǎng)絡(luò)上獲取一些數(shù)據(jù)或者計(jì)算一些東西并提供給需要這個(gè)運(yùn)算結(jié)果的activity使用。每個(gè)服務(wù)都繼承自Service基類。

l? 一個(gè)媒體播放器播放播放列表中的曲目是一個(gè)不錯(cuò)的例子。播放器應(yīng)用程序可能有一個(gè)或多個(gè)activity來給用戶選擇歌曲并進(jìn)行播放。然而,音樂播放這個(gè) 任務(wù)本身不應(yīng)該為任何activity所處理,因?yàn)橛脩羝谕谒麄冸x開播放器應(yīng)用程序而開始做別的事情時(shí),音樂仍在繼續(xù)播放。為達(dá)到這個(gè)目的,媒體播放器 activity應(yīng)該啟用一個(gè)運(yùn)行于后臺(tái)的服務(wù)。而系統(tǒng)將在這個(gè)activity不再顯示于屏幕之后,仍維持音樂播放服務(wù)的運(yùn)行。

l? 你可以連接至(綁定)一個(gè)正在運(yùn)行的服務(wù)(如果服務(wù)沒有運(yùn)行,則啟動(dòng)之)。連接之后,你可以通過那個(gè)服務(wù)暴露出來的接口與服務(wù)進(jìn)行通訊。對于音樂服務(wù)來說,這個(gè)接口可以允許用戶暫停、回退、停止以及重新開始播放。

l? 如同activity和其它組件一樣,服務(wù)運(yùn)行于應(yīng)用程序進(jìn)程的主線程內(nèi)。所以它不會(huì)對其它組件或用戶界面有任何干擾,它們一般會(huì)派生一個(gè)新線程來進(jìn)行一些耗時(shí)任務(wù)(比如音樂回放)。參見下述 進(jìn)程和線程(Processes and Threads) 。

?????????廣播接收器(Broadcast receivers)

l? 廣播接收器是一個(gè)專注于接收廣播通知信息,并做出對應(yīng)處理的組件。很多廣播是源自于系統(tǒng)代碼的──比如,通知時(shí)區(qū)改變、電池電量低、拍攝了一張照片或者用戶改變了語言選項(xiàng)。應(yīng)用程序也可以進(jìn)行廣播──比如說,通知其它應(yīng)用程序一些數(shù)據(jù)下載完成并處于可用狀態(tài)。

l? 應(yīng)用程序可以擁有任意數(shù)量的廣播接收器以對所有它感興趣的通知信息予以響應(yīng)。所有的接收器均繼承自BroadcastReceiver基類。

l? 廣播接收器沒有用戶界面。然而,它們可以啟動(dòng)一個(gè)activity來響應(yīng)它們收到的信息,或者用NotificationManager來通知用戶。通知可以用很多種方式來吸引用戶的注意力──閃動(dòng)背燈、震動(dòng)、播放聲音等等。一般來說是在狀態(tài)欄上放一個(gè)持久的圖標(biāo),用戶可以打開它并獲取消息。

?????????內(nèi)容提供者(Content providers)

l? 內(nèi)容提供者將一些特定的應(yīng)用程序數(shù)據(jù)供給其它應(yīng)用程序使用。數(shù)據(jù)可以存儲(chǔ)于文件系統(tǒng)、SQLite數(shù)據(jù)庫或其它方式。內(nèi)容提供者繼承于ContentProvider 基類,為其它應(yīng)用程序取用和存儲(chǔ)它管理的數(shù)據(jù)實(shí)現(xiàn)了一套標(biāo)準(zhǔn)方法。然而,應(yīng)用程序并不直接調(diào)用這些方法,而是使用一個(gè) ContentResolver 對象,調(diào)用它的方法作為替代。ContentResolver可以與任意內(nèi)容提供者進(jìn)行會(huì)話,與其合作來對所有相關(guān)交互通訊進(jìn)行管理。

l? 參閱獨(dú)立的內(nèi)容提供者Content Providers 章節(jié)獲得更多關(guān)于使用內(nèi)容提供者的內(nèi)容。

???????? 每當(dāng)出現(xiàn)一個(gè)需要被特定組件處理的請求時(shí),Android會(huì)確保那個(gè)組件的應(yīng)用程序進(jìn)程處于運(yùn)行狀態(tài),或在必要的時(shí)候啟動(dòng)它。并確保那個(gè)相應(yīng)組件的實(shí)例的存在,必要時(shí)會(huì)創(chuàng)建那個(gè)實(shí)例。

?

激活組件Activating components: intents

???????? 當(dāng)接收到ContentResolver發(fā)出的請求后,內(nèi)容提供者被激活。而其它三種組件──activity、服務(wù)和廣播接收器被一種叫做intent的異步消息所激活。intent是一個(gè)保存著消息內(nèi)容的Intent對 象。對于activity和服務(wù)來說,它指明了請求的操作名稱以及作為操作對象的數(shù)據(jù)的URI和其它一些信息。比如說,它可以承載對一個(gè)activity 的請求,讓它為用戶顯示一張圖片,或者讓用戶編輯一些文本。而對于廣播接收器而言,Intent對象指明了聲明的行為。比如,它可以對所有感興趣的對象聲 明照相按鈕被按下。

???????? 對于每種組件來說,激活的方法是不同的:

l? 通過傳遞一個(gè)Intent對象至?Context.startActivity()或Activity.startActivityForResult()以載入(或指定新工作給)一個(gè)activity。相應(yīng)的activity可以通過調(diào)用?getIntent()?方法來查看激活它的intent。Android通過調(diào)用activity的onNewIntent()方法來傳遞給它繼發(fā)的intent。

一個(gè)activity經(jīng)常啟動(dòng)了下一個(gè)。如果它期望它所啟動(dòng)的那個(gè)activity返回一個(gè)結(jié)果,它會(huì)以調(diào)用startActivityForResult()來取代startActivity()。比如說,如果它啟動(dòng)了另外一個(gè)activity以使用戶挑選一張照片,它也許想知道哪張照片被選中了。結(jié)果將會(huì)被封裝在一個(gè)Intent對象中,并傳遞給發(fā)出調(diào)用的activity的onActivityResult()?方法。

l? 通過傳遞一個(gè)Intent對象至Context.startService()將啟動(dòng)一個(gè)服務(wù)(或給予正在運(yùn)行的服務(wù)以一個(gè)新的指令)。Android調(diào)用服務(wù)的?onStart()方法并將Intent對象傳遞給它。

與此類似,一個(gè)Intent可以被調(diào)用組件傳遞給?Context.bindService()以獲取一個(gè)正在運(yùn)行的目標(biāo)服務(wù)的連接。這個(gè)服務(wù)會(huì)經(jīng)由onBind()?方法的調(diào)用獲取這個(gè)Intent對象(如果服務(wù)尚未啟動(dòng),bindService()會(huì)先啟動(dòng)它)。比如說,一個(gè)activity可以連接至前述的音樂回放服務(wù),并提供給用戶一個(gè)可操作的(用戶界面)以對回放進(jìn)行控制。這個(gè)activity可以調(diào)用 bindService() 來建立連接,然后調(diào)用服務(wù)中定義的對象來影響回放。

后面一節(jié):遠(yuǎn)程方法調(diào)用(Remote procedure calls)將更詳細(xì)的闡明如何綁定至服務(wù)。

l? 應(yīng)用程序可以憑借將Intent對象傳遞給?Context.sendBroadcast()?,Context.sendOrderedBroadcast(), 以及Context.sendStickyBroadcast()和其它類似方法來產(chǎn)生一個(gè)廣播。Android會(huì)調(diào)用所有對此廣播有興趣的廣播接收器的?onReceive()方法,將intent傳遞給它們。

欲了解更多intent消息的信息,請參閱獨(dú)立章節(jié) Intent和Intent濾過器(Intents and Intent Filters)。

?

關(guān)閉組件(Shutting down components)

???????? 內(nèi)容提供者僅在響應(yīng)ContentResolver提出請求的時(shí)候激活。而一個(gè)廣播接收器僅在響應(yīng)廣播信息的時(shí)候激活。所以,沒有必要去顯式的關(guān)閉這些組件。

???????? 而activity則不同,它提供了用戶界面,并與用戶進(jìn)行會(huì)話。所以只要會(huì)話依然持續(xù),哪怕對話過程暫時(shí)停頓,它都會(huì)一直保持激活狀態(tài)。與此相似,服務(wù)也會(huì)在很長一段時(shí)間內(nèi)保持運(yùn)行。所以Android為關(guān)閉activity和服務(wù)提供了一系列的方法。

l? 可以通過調(diào)用它的finish()方法來關(guān)閉一個(gè)activity。一個(gè)activity可以通過調(diào)用另外一個(gè)activity(它用startActivityForResult()?啟動(dòng)的)的finishActivity()方法來關(guān)閉它。

l? 服務(wù)可以通過調(diào)用它的stopSelf()方法來停止,或者調(diào)用?Context.stopService()。

系統(tǒng)也會(huì)在組件不再被使用的時(shí)候或者Android需要為活動(dòng)組件聲明更多內(nèi)存的時(shí)候關(guān)閉它。后面的<activity>元素的name屬性指定了實(shí)現(xiàn)了這個(gè)activity的 Activity的子類。icon和label屬性指向了包含展示給用戶的此activity的圖標(biāo)和標(biāo)簽的資源文件。

???????? 其它組件也以類似的方法聲明──<service>?元素用于聲明服務(wù),?<receiver>?元素用于聲明廣播接收器,而<provider>?元素用于聲明內(nèi)容提供者。 manifest文件中未進(jìn)行聲明的activity、服務(wù)以及內(nèi)容提供者將不為系統(tǒng)所見,從而也就不會(huì)被運(yùn)行。然而,廣播接收器既可以在manifest文件中聲明,也可以在代碼中進(jìn)行動(dòng)態(tài)的創(chuàng)建,并以調(diào)用Context.registerReceiver()的方式注冊至系統(tǒng)。

???????? 欲更多了解如何為你的應(yīng)用程序構(gòu)建manifest文件,請參閱AndroidManifest.xml文件一章。

?

Intent過濾器(Intent filters)

???????? Intent對象可以被顯式的指定目標(biāo)組件。如果進(jìn)行了這種指定,Android會(huì)找到這個(gè)組件(依據(jù)manifest文件中的聲明)并激活它。但如果 Intent沒有進(jìn)行顯式的指定,Android就必須為它找到對于intent來說最合適的組件。這個(gè)過程是通過比較Intent對象和所有可能對象的intent過濾器完成的。組件的intent過濾器會(huì)告知Android它所能處理的intent類型。如同其它相對于組件很重要的信息一樣,這些是在manifest文件中進(jìn)行聲明的。這里是上面實(shí)例的一個(gè)擴(kuò)展,其中加入了針對activity的兩個(gè)intent過濾器聲明:

?

示例中的第一個(gè)過濾器──action “android.intent.action.MAIN”和類別“android.intent.category.LAUNCHER”的組合──是通常具有的。它標(biāo)明了這個(gè)activity將在應(yīng)用程序加載器中顯示,就是用戶在設(shè)備上看到的可供加載的應(yīng)用程序列表。換句話說,這個(gè)activity是應(yīng)用程序的入口,是用戶選擇運(yùn)行這個(gè)應(yīng)用程序后所見到的第一個(gè)activity。

???????? 第二個(gè)過濾器聲明了這個(gè)activity能被賦予一種特定類型的數(shù)據(jù)。

???????? 組件可以擁有任意數(shù)量的intent過濾器,每個(gè)都會(huì)聲明一系列不同的能力。如果它沒有包含任何過濾器,它將只能被顯式聲明了目標(biāo)組件名稱的intent激活。

???????? 對于在代碼中創(chuàng)建并注冊的廣播接收器來說,intent過濾器將被直接以 IntentFilter對象實(shí)例化。其它過濾器則在manifest文件中設(shè)置。

???????? 欲獲得更多intent過濾器的信息,請參閱獨(dú)立章節(jié): Intent和Intent過濾器。

?

Activity和任務(wù)(Activities and Tasks)

???????? 如前所述,一個(gè)activity可以啟動(dòng)另外一個(gè),甚至包括與它不處于同一應(yīng)用程序之中的。舉個(gè)例子說,假設(shè)你想讓用戶看到某個(gè)地方的街道地圖。而已經(jīng)存 在一個(gè)具有此功能的activity了,那么你的activity所需要做的工作就是把請求信息放到一個(gè)Intent對象里面,并把它傳遞給startActivity()。于是地圖瀏覽器就會(huì)顯示那個(gè)地圖。而當(dāng)用戶按下BACK鍵的時(shí)候,你的activity又會(huì)再一次的顯示在屏幕上。

???????? 對于用戶來說,這看起來就像是地圖瀏覽器是你activity所在的應(yīng)用程序中的一個(gè)組成部分,其實(shí)它是在另外一個(gè)應(yīng)用程序中定義,并運(yùn)行在那個(gè)應(yīng)用程序的進(jìn)程之中的。Android將這兩個(gè)activity放在同一個(gè)任務(wù)中 來維持一個(gè)完整的用戶體驗(yàn)。簡單的說,任務(wù)就是用戶所體驗(yàn)到的“應(yīng)用程序”。它是安排在一個(gè)堆棧中的一組相關(guān)的activity。堆棧中的根 activity就是啟動(dòng)了這整個(gè)任務(wù)的那個(gè)──一般情況下,它就是用戶在應(yīng)用程序加載器中所選擇的。而堆棧最上方的activity則是當(dāng)前運(yùn)行的── 用戶直接對其進(jìn)行操作的。當(dāng)一個(gè)activity啟動(dòng)另外一個(gè)的時(shí)候,新的activity就被壓入堆棧,并成為當(dāng)前運(yùn)行的activity。而前一個(gè) activity仍保持在堆棧之中。當(dāng)用戶按下BACK鍵的時(shí)候,當(dāng)前activity出棧,而前一個(gè)恢復(fù)為當(dāng)前運(yùn)行的activity。

???????? 堆棧中保存的其實(shí)是對象,所以如果發(fā)生了諸如需要多個(gè)地圖瀏覽器的情況,就會(huì)使得一個(gè)任務(wù)中出現(xiàn)多個(gè)同一Activity子類的實(shí)例同時(shí)存在,堆棧會(huì)為每個(gè)實(shí)例單獨(dú)開辟一個(gè)入口。堆棧中的Activity永遠(yuǎn)不會(huì)重排,只會(huì)壓入或彈出。

???????? 任務(wù)其實(shí)就是activity的堆棧,而不是manifest文件中的一個(gè)類或者元素。所以你無法撇開activity而為一個(gè)任務(wù)設(shè)置一個(gè)值。而事實(shí)上 整個(gè)任務(wù)使用的值是在根activity中設(shè)置的。比如說,下一節(jié)我們會(huì)談及“任務(wù)的affinity”,從affinity中讀出的值將會(huì)設(shè)置到任務(wù)的 根activity之中。

???????? 任務(wù)中的所有activity是作為一個(gè)整體進(jìn)行移動(dòng)的。整個(gè)的任務(wù)(即activity堆棧)可以移到前臺(tái),或退至后臺(tái)。舉個(gè)例子說,比如當(dāng)前任務(wù)在堆 棧中存有四個(gè)activity──三個(gè)在當(dāng)前activity之下。當(dāng)用戶按下HOME鍵的時(shí)候,回到了應(yīng)用程序加載器,然后選擇了一個(gè)新的應(yīng)用程序(也 就是一個(gè)新任務(wù))。則當(dāng)前任務(wù)遁入后臺(tái),而新任務(wù)的根activity顯示出來。然后,過了一小會(huì)兒,用戶再次回到了應(yīng)用程序加載器而又選擇了前一個(gè)應(yīng)用程序(上一個(gè)任務(wù))。于是那個(gè)任務(wù),帶著它堆棧中所有的四個(gè)activity,再一次的到了前臺(tái)。當(dāng)用戶按下BACK鍵的時(shí)候,屏幕不會(huì)顯示出用戶剛才離開的activity(上一個(gè)任務(wù)的根activity)。取而代之,當(dāng)前任務(wù)的堆棧中最上面的activity被彈出,而同一任務(wù)中的上一個(gè)activity顯示了出來。

?????????上述的種種即是activity和任務(wù)的默認(rèn)行為模式。但是有一些方法可以改變所有這一切。activity和任務(wù)的聯(lián)系、任務(wù)中activity的行為 方式都被啟動(dòng)那個(gè)activity的Intent對象中設(shè)置的一系列標(biāo)記和manifest文件中那個(gè)activity中的<activity>元素的系列屬性之間的交互所控制。無論是請求發(fā)出者和回應(yīng)者在這里都擁有話語權(quán)。

???????? 我們剛才所說的這些關(guān)鍵Intent標(biāo)記如下:

?????????????????? FLAG_ACTIVITY_NEW_TASK

FLAG_ACTIVITY_CLEAR_TOP

FLAG_ACTIVITY_RESET_TASK_IF_NEEDED

FLAG_ACTIVITY_SINGLE_TOP

???????? 而關(guān)鍵的<activity>屬性是:

?????????????????? taskAffinity

launchMode

allowTaskReparenting

clearTaskOnLaunch

alwaysRetainTaskState

finishOnTaskLaunch

???????? 接下來的一節(jié)會(huì)描述這些標(biāo)記以及屬性的作用,它們是如何互相影響的,以及控制它們的使用時(shí)必須考慮到的因素。

?

任務(wù)共用性和新任務(wù)Affinities and new tasks

???????? 默認(rèn)情況下,一個(gè)應(yīng)用程序中的activity相互之間會(huì)有一種Affinity──也就是說,它們首選都?xì)w屬于一個(gè)任務(wù)。然而,可以在<activity>元素中把每個(gè)activity的taskAffinity屬 性設(shè)置為一個(gè)獨(dú)立的affinity。于是在不同的應(yīng)用程序中定義的activity可以享有同一個(gè)affinity,或者在同一個(gè)應(yīng)用程序中定義的 activity有著不同的affinity。affinity在兩種情況下生效:當(dāng)加載activity的Intent對象包含了FLAG_ACTIVITY_NEW_TASK 標(biāo)記,或者當(dāng)activity的allowTaskReparenting屬性設(shè)置為“true”。

?????????FLAG_ACTIVITY_NEW_TASK標(biāo)記

?????????????????? 如前所述,在默認(rèn)情況下,一個(gè)新activity被另外一個(gè)調(diào)用了startActivity()方法的activity載入了任務(wù)之中。并壓入了調(diào)用者所在的堆棧。然而,如果傳遞給startActivity()的Intent對象包含了FLAG_ACTIVITY_NEW_TASK標(biāo)記,系統(tǒng)會(huì)為新activity安排另外一個(gè)任務(wù)。一般情況下,如同標(biāo)記所暗示的那樣,這會(huì)是一個(gè)新任務(wù)。然而,這并不是必然的。如果已經(jīng)存在了一個(gè)與新activity有著同樣affinity的任務(wù),則activity會(huì)載入那個(gè)任務(wù)之中。如果沒有,則啟用新任務(wù)。

?????????allowTaskReparenting?屬性

?????????????????? 如果一個(gè)activity將allowTaskReparenting屬 性設(shè)置為“true”。它就可以從初始的任務(wù)中轉(zhuǎn)移到與其擁有同一個(gè)affinity并轉(zhuǎn)向前臺(tái)的任務(wù)之中。比如說,一個(gè)旅行應(yīng)用程序中包含的預(yù)報(bào)所選城 市的天氣情況的activity。它與這個(gè)應(yīng)用程序中其它的activity擁有同樣的affinity(默認(rèn)的affinity)而且允許重定父級。你 的另一個(gè)activity啟動(dòng)了天氣預(yù)報(bào),于是它就會(huì)與這個(gè)activity共處與同一任務(wù)之中。然而,當(dāng)那個(gè)旅行應(yīng)用程序再次回到前臺(tái)的時(shí)候,這個(gè)天氣 預(yù)報(bào)activity就會(huì)被再次安排到原先的任務(wù)之中并顯示出來。

???????? 如果在用戶的角度看來,一個(gè).apk文件中包含了多于一個(gè)的“應(yīng)用程序”,你可能會(huì)想要為它們所轄的activity安排不一樣的affinity。

?

加載模式(Launch modes)

???????? <activity>元素的launchMode屬性可以設(shè)置四種不同的加載模式:

"standard" (默認(rèn)模式)

"singleTop"

"singleTask"

"singleInstance"

???????? 這些模式之間的差異主要體現(xiàn)在四個(gè)方面:

l??哪個(gè)任務(wù)會(huì)把持對intent做出響應(yīng)的activity。對“standard”和“singleTop”模式而言,是產(chǎn)生intent(并調(diào)用startActivity())的任務(wù)──除非Intent對象包含F(xiàn)LAG_ACTIVITY_NEW_TASK標(biāo)記。而在這種情況下,如同上面Affinitie和新任務(wù)一節(jié)所述,會(huì)是另外一個(gè)任務(wù)。

相反,對“singleTask”和“singleInstance”模式而言,activity總是位于任務(wù)的根部。正是它們定義了一個(gè)任務(wù),所以它們絕不會(huì)被載入到其它任務(wù)之中。

l??activity是否可以存在多個(gè)實(shí)例。一個(gè)“standard”或“singleTop”的activity可以被多次初始化。它們可以歸屬于多個(gè)任務(wù),而一個(gè)任務(wù)也可以擁有同一activity的多個(gè)實(shí)例。

相反,對“singleTask”和“singleInstance”的activity被限定于只能有一個(gè)實(shí)例。因?yàn)檫@些activity都是任務(wù)的起源,這種限制意味著在一個(gè)設(shè)備中同一時(shí)間只允許存在一個(gè)任務(wù)的實(shí)例。

l??在實(shí)例所在的任務(wù)中是否會(huì)有別的activity一個(gè)“singleInstance”模式的activity將會(huì)是它所在的任務(wù)中唯一的activity。如果它啟動(dòng)了別的activity,那個(gè)activity將會(huì)依據(jù)它自己的加載模式加載到其它的任務(wù)中去──如同在intent中設(shè)置了FLAG_ACTIVITY_NEW_TASK 標(biāo)記一樣的效果。在其它方面,“singleInstance”模式的效果與“singleTask”是一樣的。

剩下的三種模式允許一個(gè)任務(wù)中出現(xiàn)多個(gè)activity?!皊ingleTask”模式的activity將是任務(wù)的根activity,但它可以啟動(dòng)別的activity并將它們置入所在的任務(wù)中。“standard”和“singleTop”activity則可以在堆棧的任意位置出現(xiàn)。

l??是否要載入新的類實(shí)例以處理新的intent對默認(rèn)的"standard"模式來說,對于每個(gè)新intent都會(huì)創(chuàng)建一個(gè)新的實(shí)例以進(jìn)行響應(yīng),每個(gè)實(shí)例僅處理一個(gè)intent?!皊ingleTop”模式下,如果activity位于目的任務(wù)堆棧的最上面,則重用目前現(xiàn)存的activity來處理新的intent。如果它不是在堆棧頂部,則不會(huì)發(fā)生重用。而是創(chuàng)建一個(gè)新實(shí)例來處理新的intent并將其推入堆棧。

舉例來說,假設(shè)一個(gè)任務(wù)的堆棧由根activityA和activity B、C和位于堆棧頂部的D組成,即堆棧A-B-C-D。一個(gè)針對D類型的activity的intent抵達(dá)的時(shí)候,如果D是默認(rèn)的“standard”加載模式,則創(chuàng)建并加載一個(gè)新的類實(shí)例,于是堆棧變?yōu)锳-B-C-D-D。 然而,如果D的載入模式為“singleTop”,則現(xiàn)有的實(shí)例會(huì)對新intent進(jìn)行處理(因?yàn)樗挥诙褩m敳?#xff09;而堆棧保持A-B-C-D的形態(tài)。

換言之,如果新抵達(dá)的intent是針對B類型的activity,則無論B的模式是“standard”還是“singleTop” ,都會(huì)加載一個(gè)新的B的實(shí)例(因?yàn)锽不位于堆棧的頂部),而堆棧的順序變?yōu)锳-B-C-D-B。

如前所述,“singleTask”或“singleInstance”模式的activity永遠(yuǎn)不會(huì)存在多于一個(gè)實(shí)例。所以實(shí)例將處理所有新的intent。一個(gè)“singleInstance”模式的activity永遠(yuǎn)保持在堆棧的頂部(因?yàn)樗悄莻€(gè)堆棧中唯一的一個(gè)activity),所以它一直堅(jiān)守在處理intent的崗位上。然而,對一個(gè)“singleTask”模式的activity來說,它上面可能有,也可能沒有別的activity和它處于同一堆棧。在有的情況下,它就不在能夠處理intent的位置上,則那個(gè)intent將被舍棄。(即便在intent被舍棄的情況下,它的抵達(dá)仍將使這個(gè)任務(wù)切換至前臺(tái),并一直保留)

???????? 當(dāng)一個(gè)現(xiàn)存的activity被要求處理一個(gè)新的intent的時(shí)候,會(huì)調(diào)用onNewIntent()方法來將intent對象傳遞至activity。(啟動(dòng)activity的原始intent對象可以通過調(diào)用getIntent()方法獲得。)

???????? 請注意,當(dāng)一個(gè)新的activity實(shí)例被創(chuàng)建以處理新的intent的時(shí)候,用戶總可以按下BACK鍵來回到前面的狀態(tài)(回到前一個(gè) activity)。但當(dāng)使用現(xiàn)存的activity來處理新intent的時(shí)候,用戶是不能靠按下BACK鍵回到當(dāng)這個(gè)新intent抵達(dá)之前的狀態(tài) 的。

???????? 想獲得更多關(guān)于加載模式的內(nèi)容,請參閱?<activity>?元素的描述。

?

清理堆棧(Clearing the stack)

???????? 如果用戶離開一個(gè)任務(wù)很長一段時(shí)間,系統(tǒng)會(huì)清理該任務(wù)中除了根activity之外的所有activity。當(dāng)用戶再次回到這個(gè)任務(wù)的時(shí)候,除了只剩下初 始化activity尚存之外,其余都跟用戶上次離開它的時(shí)候一樣。這樣做的原因是:在一段時(shí)間之后,用戶再次回到一個(gè)任務(wù)的時(shí)候,他們更期望放棄他們之 前的所作所為,做些新的事情。

???????? 這些屬于默認(rèn)行為,另外,也存在一些activity的屬性用以控制并改變這些行為:

?????????alwaysRetainTaskState?屬性

?????????????????? 如果一個(gè)任務(wù)的根activity中此屬性設(shè)置為“true”,則上述默認(rèn)行為不會(huì)發(fā)生。任務(wù)將在很長的一段時(shí)間內(nèi)保留它堆棧內(nèi)的所有activity。

?????????clearTaskOnLaunch屬性

?????????????????? 如果一個(gè)任務(wù)的根activity中此屬性設(shè)置為“true”,則每當(dāng)用戶離開這個(gè)任務(wù)和返回它的時(shí)候,堆棧都會(huì)被清空至只留下rootactivity。換句話說,這是alwaysRetainTaskState的另一個(gè)極端。哪怕僅是過了一小會(huì)兒,用戶回到任務(wù)時(shí),也是見到它的初始狀態(tài)。

?????????finishOnTaskLaunch屬性

?????????????????? 這個(gè)屬性與clearTaskOnLaunch屬性相似,但它僅作用于單個(gè)的activity,而不是整個(gè)的task。而且它可以使任意activity都被清理,甚至根activity也不例外。當(dāng)它設(shè)置為“true”的時(shí)候,此activity僅做為任務(wù)的一部分存在于當(dāng)前回話中,一旦用戶離開并再次回到這個(gè)任務(wù),此activity將不復(fù)存在。

???????? 此外,還有別的方式從堆棧中移除一個(gè)activity。如果一個(gè)intent對象包含F(xiàn)LAG_ACTIVITY_CLEAR_TOP標(biāo)記,而且目標(biāo)任務(wù)的堆棧中已經(jīng)存在了一個(gè)能夠響應(yīng)此intent的activity類型的實(shí)例。則這個(gè)實(shí)例之上的所有activity都將被清理以使它位于堆棧的頂部來對intent做出響應(yīng)。如果此時(shí)指定的activity的加載模式為“standard”,則它本身也會(huì)從堆棧中移除,并加載一個(gè)新的實(shí)例來處理到來的intent。這是因?yàn)榧虞d模式為“standard”的activity總會(huì)創(chuàng)建一個(gè)新實(shí)例來處理新的intent。

???????? FLAG_ACTIVITY_CLEAR_TOP與FLAG_ACTIVITY_NEW_TASK經(jīng)常合并使用。這時(shí),這些標(biāo)記提供了一種定位其它任務(wù)中現(xiàn)存的activity并將它們置于可以對intent做出響應(yīng)的位置的方法。

?

啟動(dòng)任務(wù)(Starting tasks)

???????? 當(dāng)一個(gè)activity被指定一個(gè)“android.intent.action.MAIN”做為動(dòng)作,以及“android.intent.category.LAUNCHER”做為類別的intent過濾器之后(在前述intent過濾器一節(jié)中已經(jīng)有了這個(gè)示例),它就被設(shè)置為一個(gè)任務(wù)的入口點(diǎn)。這樣的過濾器設(shè)置會(huì)在應(yīng)用程序加載器中為此activity顯示一個(gè)圖標(biāo)和標(biāo)簽,以供用戶加載任務(wù)或加載之后在任意時(shí)間回到這個(gè)任務(wù)。

???????? 第二個(gè)能力相當(dāng)重要:用戶必須可以離開一個(gè)任務(wù),并在一段時(shí)間后返回它。出于這個(gè)考慮,加載模式被設(shè)定為“singleTask”和“singleInstance”的activity總是會(huì)初始化一個(gè)新任務(wù),這樣的activity僅能用于指定了一個(gè)MAIN和LAUNCHER過濾器的情況之下。我們來舉例說明如果沒指定過濾器的情況下會(huì)發(fā)生的事情:一個(gè)intent加載了一個(gè)“singleTask”的activity,初始化了一個(gè)新任務(wù),用戶在這個(gè)任務(wù)中花費(fèi)了一些時(shí)間來完成工作。然后用戶按下了HOME鍵。于是任務(wù)被要求轉(zhuǎn)至后臺(tái)并被主屏幕所掩蓋。因?yàn)樗]有在應(yīng)用程序加載器中顯示圖標(biāo),這將導(dǎo)致用戶無法再返回它。

???????? 類似的困境也可由FLAG_ACTIVITY_NEW_TASK標(biāo)記引起。如果此標(biāo)記使一個(gè)activity啟動(dòng)了一個(gè)新任務(wù)繼而用戶按下了HOME鍵離開了它,則用戶必須要有一些方法再次回到這個(gè)任務(wù)。一些實(shí)體(諸如通知管理器)總是在另外的任務(wù)中啟動(dòng)新activity,而不是做為它們自己的一部分,所以它們總是將FLAG_ACTIVITY_NEW_TASK標(biāo)記包含在intent里面并傳遞給startActivity()。如果你寫了一個(gè)能被外部實(shí)體使用這個(gè)標(biāo)記調(diào)用的activity,你必須注意要給用戶留一個(gè)返回這個(gè)被外部實(shí)體啟動(dòng)的任務(wù)的方法。

???????? 當(dāng)你不想讓用戶再次返回一個(gè)activity的情況下,可以將?<activity>?元素的 finishOnTaskLaunch設(shè)置為“true”。參見前述View.onKeyDown()這樣報(bào)告用戶動(dòng)作以及后面 線程一節(jié)所敘述的那樣,為這些長時(shí)間操作衍生出一個(gè)單獨(dú)的線程進(jìn)行處理。

???????? 在可用內(nèi)存不足而又有一個(gè)正在為用戶進(jìn)行服務(wù)的進(jìn)程需要更多內(nèi)存的時(shí)候,Android有時(shí)候可能會(huì)關(guān)閉一個(gè)進(jìn)程。而在這個(gè)進(jìn)程中運(yùn)行著的應(yīng)用程序也因此被銷毀。當(dāng)再次出現(xiàn)需要它們進(jìn)行處理的工作的時(shí)候,會(huì)為這些組件重新創(chuàng)建進(jìn)程。

???????? 在決定結(jié)束哪個(gè)進(jìn)程的時(shí)候,Android會(huì)衡量它們對于用戶的相對重要性。比如說,相對于一個(gè)仍有用戶可見的activity的進(jìn)程,它更有可能去關(guān)閉 一個(gè)其activity已經(jīng)不為用戶所見的進(jìn)程。也可以說,決定是否關(guān)閉一個(gè)進(jìn)程主要依據(jù)在那個(gè)進(jìn)程中運(yùn)行的組件的狀態(tài)。這些狀態(tài)將在后續(xù)的一節(jié)Thread對象創(chuàng)建的。Android提供了很多便于管理線程的類: Looper用于在一個(gè)線程中運(yùn)行一個(gè)消息循環(huán), Handler用于處理消息,HandlerThread 用于使用一個(gè)消息循環(huán)啟用一個(gè)線程。

?

遠(yuǎn)程方法調(diào)用(Remote procedure calls)

???????? Android有一個(gè)輕量級的遠(yuǎn)程方法調(diào)用(RPC)機(jī)制:即在本地調(diào)用一個(gè)方法,但在遠(yuǎn)程(其它的進(jìn)程中)進(jìn)行處理,然后將結(jié)果返回調(diào)用者。這將方法調(diào)用及其附屬的數(shù)據(jù)以系統(tǒng)可以理解的方式進(jìn)行分離,并將其從本地進(jìn)程和本地地址空間傳送至遠(yuǎn)程過程和遠(yuǎn)程地址空間,并在那里重新裝配并對調(diào)用做出反應(yīng)。返回 的結(jié)果將以相反的方向進(jìn)行傳遞。Android提供了完成這些工作所需的所有的代碼,以使你可以集中精力來實(shí)現(xiàn)RPC接口本身。

???????? RPC接口可以只包括方法。即便沒有返回值,所有方法仍以同步的方式執(zhí)行(本地方法阻塞直至遠(yuǎn)程方法結(jié)束)。

???????? 簡單的說,這套機(jī)制是這樣工作的:一開始,你用簡單的IDL(界面描繪語言)聲明一個(gè)你想要實(shí)現(xiàn)的RPC接口。然后用?aidl?工具為這個(gè)聲明生成一個(gè)Java接口定義,這個(gè)定義必須對本地和遠(yuǎn)程進(jìn)程都可見。它包含兩個(gè)內(nèi)部類,如下圖所示:

?

???????? 內(nèi)部類中有管理實(shí)現(xiàn)了你用IDL聲明的接口的遠(yuǎn)程方法調(diào)用所需要的所有代碼。兩個(gè)內(nèi)部類均實(shí)現(xiàn)了 IBinder接口。一個(gè)用于系統(tǒng)在本地內(nèi)部使用,你些的代碼可以忽略它;另外一個(gè),我們稱為Stub,擴(kuò)展了Binder類。除了實(shí)現(xiàn)了IPC調(diào)用的內(nèi)部代碼之外,它還包括了你聲明的RPC接口中的方法的聲明。你應(yīng)該如上圖所示的那樣寫一個(gè)Stub的子類來實(shí)現(xiàn)這些方法。

???????? 一般情況下,遠(yuǎn)程過程是被一個(gè)服務(wù)所管理的(因?yàn)榉?wù)可以通知系統(tǒng)關(guān)于進(jìn)程以及它連接到別的進(jìn)程的信息)。它包含著 aidl工具產(chǎn)生的接口文件和實(shí)現(xiàn)了RPC方法的Stub的子類。而客戶端只需要包括aidl工具產(chǎn)生的接口文件。

???????? 下面將說明服務(wù)與其客戶端之間的連接是如何建立的:

l? 服務(wù)的客戶端(位于本地)應(yīng)該實(shí)現(xiàn)?onServiceConnected()?和?onServiceDisconnected()?方法。這樣,當(dāng)至遠(yuǎn)程服務(wù)的連接成功建立或者斷開的時(shí)候,它們會(huì)收到通知。這樣它們就可以調(diào)用?bindService()?來設(shè)置連接。

l? 而服務(wù)則應(yīng)該實(shí)現(xiàn)?onBind()?方法以接受或拒絕連接。這取決于它收到的intent(intent將傳遞給bindService())。如果接受了連接,它會(huì)返回一個(gè)Stub的子類的實(shí)例。

l? 如果服務(wù)接受了連接,Android將會(huì)調(diào)用客戶端的onServiceConnected() 方法,并傳遞給它一個(gè)IBinder對象,它是由服務(wù)所管理的Stub的子類的代理。通過這個(gè)代理,客戶端可以對遠(yuǎn)程服務(wù)進(jìn)行調(diào)用。

?

線程安全方法(Thread-safe methods)

???????? 在一些情況下,你所實(shí)現(xiàn)的方法有可能會(huì)被多于一個(gè)的線程所調(diào)用,所以它們必須被寫成線程安全的。

???????? 對于我們上一節(jié)所討論的RPC機(jī)制中的可以被遠(yuǎn)程調(diào)用的方法來說,這是必須首先考慮的。如果針對一個(gè)IBinder對象中實(shí)現(xiàn)的方法的調(diào)用源自這個(gè) IBinder對象所在的進(jìn)程時(shí),這個(gè)方法將會(huì)在調(diào)用者的線程中執(zhí)行。然而,如果這個(gè)調(diào)用源自其它的進(jìn)程,則這個(gè)方法將會(huì)在一個(gè)線程池中選出的線程中運(yùn) 行,這個(gè)線程池由Android加以管理,并與IBinder存在于同一進(jìn)程內(nèi);這個(gè)方法不會(huì)在進(jìn)程的主線程內(nèi)執(zhí)行。反過來說,一個(gè)服務(wù)的 onBind() 方法應(yīng)為服務(wù)進(jìn)程的主線程所調(diào)用,而實(shí)現(xiàn)了由 onBind() 返回的對象(比如說,一個(gè)實(shí)現(xiàn)了RPC方法的Stub的子類)的方法將為池中的線程所調(diào)用。因?yàn)榉?wù)可以擁有多于一個(gè)的客戶端,而同一時(shí)間,也會(huì)有多個(gè)池中的線程調(diào)用同一個(gè)IBinder方法。因此IBinder方法必須實(shí)現(xiàn)為線程安全的。

???????? 類似的,一個(gè)內(nèi)容提供者能接受源自其它進(jìn)程的請求數(shù)據(jù)。盡管ContentResolver和ContentProvider類隱藏了交互溝通過程的管理細(xì)節(jié),ContentProvider會(huì)由query(),?insert(),?delete(),?update()和getType()方法來相應(yīng)這些請求,而這些方法也都是由那個(gè)內(nèi)容提供者的進(jìn)程中所包涵的線程池提供的,而不是進(jìn)程的主線程本身。所以這些有可能在同一時(shí)間被很多線程調(diào)用的方法也必須被實(shí)現(xiàn)為線程安全的。

?

組件生命周期(Component Lifecycles)

應(yīng)用程序組件有其生命周期──由Android初始化它們以相應(yīng)intent直到這個(gè)實(shí)例被摧毀。在此之間,它們有時(shí)是激活的有時(shí)則相反?;蛘?#xff0c;如果它是 一個(gè)activity,則是可為用戶所見或者不能。這一節(jié)討論了activity、服務(wù)以及廣播接收器的生命周期,包括它們在生命周期中的狀態(tài)、在狀態(tài)之 間轉(zhuǎn)變時(shí)通知你的方法、以及當(dāng)這些進(jìn)程被關(guān)閉或?qū)嵗淮輾r(shí),這些狀態(tài)產(chǎn)生的效果。

?

Activity生命周期(Activity lifecycle)

???????? 一個(gè)activity主要有三個(gè)狀態(tài):

l? 當(dāng)在屏幕前臺(tái)時(shí)(位于當(dāng)前任務(wù)堆棧的頂部),它是活躍或運(yùn)行的狀態(tài)。它就是相應(yīng)用戶操作的activity。

l? 當(dāng)它失去焦點(diǎn)但仍然對用戶可見時(shí),它處于暫停狀態(tài)。即是:在它之上有另外一個(gè)activity。這個(gè)activity也許是透明的,或者未能完全遮蔽全屏,所以被暫停的activity仍對用戶可見。暫停的activity仍然是存活狀態(tài)(它保留著所有的狀態(tài)和成員信息并連接至窗口管理器),但當(dāng)系統(tǒng)處于極低內(nèi)存的情況下,仍然可以殺死這個(gè)activity。

l? 如果它完全被另一個(gè)activity覆蓋是,它處于停止?fàn)顟B(tài)。它仍然保留所有的狀態(tài)和成員信息。然而它不在為用戶可見,所以它的窗口將被隱藏,如果其它地方需要內(nèi)存,則系統(tǒng)經(jīng)常會(huì)殺死這個(gè)activity。

如果一個(gè)activity處于暫停或停止?fàn)顟B(tài),系統(tǒng)可以通過要求它結(jié)束(調(diào)用它的 finish() 方法)或直接殺死它的進(jìn)程來將它驅(qū)出內(nèi)存。當(dāng)它再次為用戶可見的時(shí)候,它只能完全重新啟動(dòng)并恢復(fù)至以前的狀態(tài)。

當(dāng)一個(gè)activity從這個(gè)狀態(tài)轉(zhuǎn)變到另一個(gè)狀態(tài)時(shí),它被以下列protected方法所通知:

???????? void onCreate(Bundle savedInstanceState)

void onStart()

void onRestart()

void onResume()

void onPause()

void onStop()

void onDestroy()

???????? 你可以重載所有這些方法以在狀態(tài)改變時(shí)進(jìn)行合適的工作。所有的activity都必須實(shí)現(xiàn)?onCreate()?用以當(dāng)對象第一次實(shí)例化時(shí)進(jìn)行初始化設(shè)置。很多activity會(huì)實(shí)現(xiàn)?onPause()以提交數(shù)據(jù)變化或準(zhǔn)備停止與用戶的交互。

?

調(diào)用父類(Calling into the superclass)

???????? 所有activity生命周期方法的實(shí)現(xiàn)都必須先調(diào)用其父類的版本。比如說:

?????????

???????? 總得來說,這七個(gè)方法定義了一個(gè)activity完整的生命周期。實(shí)現(xiàn)這些方法可以幫助你監(jiān)察三個(gè)嵌套的生命周期循環(huán):

l? 一個(gè)activity?完整的生命周期?自第一次調(diào)用 onCreate()開始,直至調(diào)用onDestroy()為止。activity在onCreate()中設(shè)置所有“全局”狀態(tài)以完成初始化,而在onDestroy()中釋放所有系統(tǒng)資源。比如說,如果activity有一個(gè)線程在后臺(tái)運(yùn)行以從網(wǎng)絡(luò)上下載數(shù)據(jù),它會(huì)以 onCreate()創(chuàng)建那個(gè)線程,而以?onDestroy()銷毀那個(gè)線程。

l? 一個(gè)activity的?可視生命周期自 onStart() 調(diào)用開始直到相應(yīng)的 onStop()調(diào)用。在此期間,用戶可以在屏幕上看到此activity,盡管它也許并不是位于前臺(tái)或者正在與用戶做交互。在這兩個(gè)方法中,你可以管控用來向用戶顯示這個(gè)activity的資源。比如說,你可以在onStart() 中注冊一個(gè)BroadcastReceiver 來監(jiān)控會(huì)影響到你UI的改變,而在onStop() 中來取消注冊,這時(shí)用戶是無法看到你的程序顯示的內(nèi)容的。onStart() 和 onStop() 方法可以隨著應(yīng)用程序是否為用戶可見而被多次調(diào)用。

l? 一個(gè)activity的?前臺(tái)生命周期?自 onResume() 調(diào)用起,至相應(yīng)的 onPause()調(diào)用為止。在此期間,activity位于前臺(tái)最上面并與用戶進(jìn)行交互。activity會(huì)經(jīng)常在暫停和恢復(fù)之間進(jìn)行狀態(tài)轉(zhuǎn)換──比如說當(dāng)設(shè)備轉(zhuǎn)入休眠狀態(tài)或有新的activity啟動(dòng)時(shí),將調(diào)用onPause() 方法。當(dāng)activity獲得結(jié)果或者接收到新的intent的時(shí)候會(huì)調(diào)用onResume() 方法。因此,在這兩個(gè)方法中的代碼應(yīng)當(dāng)是輕量級的。

下圖展示了上述循環(huán)過程以及activity在這個(gè)過程之中歷經(jīng)的狀態(tài)改變。著色的橢圓是activity可以經(jīng)歷的主要狀態(tài)。矩形框代表了當(dāng)activity在狀態(tài)間發(fā)生改變的時(shí)候,你進(jìn)行操作所要實(shí)現(xiàn)的回調(diào)方法。

?

???????? 下表詳細(xì)描述了這些方法,并在activity的整個(gè)生命周期中定位了它們。

方法

描述

是否可被殺死(Killable?)

下一個(gè)

onCreate()

在activity第一次被創(chuàng)建的時(shí)候調(diào)用。這里是你做所有初始化設(shè)置的地方──創(chuàng)建視圖、綁定數(shù)據(jù)至列表等。如果曾經(jīng)有狀態(tài)記錄(參閱后述Saving Activity State。),則調(diào)用此方法時(shí)會(huì)傳入一個(gè)包含著此activity以前狀態(tài)的包對象做為參數(shù)。

接下來始終遵循調(diào)用onStart()。

onStart()

onRestart()

在activity停止后,在再次啟動(dòng)之前被調(diào)用。

接下來始終遵循調(diào)用onStart()。

onStart()

onStart()

當(dāng)activity正要變得為用戶所見時(shí)被調(diào)用。

當(dāng)activity轉(zhuǎn)向前臺(tái)時(shí)接下來調(diào)用onResume(),在activity變?yōu)殡[藏時(shí)接下來調(diào)用onStop()。

onResume()

onStop()

onResume()

在activity開始與用戶進(jìn)行交互之前被調(diào)用。此時(shí)activity位于堆棧頂部,并接受用戶輸入。

接下來始終遵循調(diào)用onPause()。

onPause()

onPause()

當(dāng)系統(tǒng)將要啟動(dòng)另一個(gè)activity時(shí)調(diào)用。此方法主要用來將未保存的變化進(jìn)行持久化,停止類似動(dòng)畫這樣耗費(fèi)CPU的動(dòng)作等。這一切動(dòng)作應(yīng)該在短時(shí)間內(nèi)完成,因?yàn)橄乱粋€(gè)activity必須等到此方法返回后才會(huì)繼續(xù)。

當(dāng)activity重新回到前臺(tái)時(shí)接下來調(diào)用onResume()。當(dāng)activity變?yōu)橛脩舨豢梢姇r(shí)接下來調(diào)用onStop()。

onResume()

onStop()

onStop()

當(dāng)activity不再為用戶可見時(shí)調(diào)用此方法。這可能發(fā)生在它被銷毀或者另一個(gè)activity(可能是現(xiàn)存的或者是新的)回到運(yùn)行狀態(tài)并覆蓋了它。

如果activity再次回到前臺(tái)跟用戶交互則接下來調(diào)用onRestart(),如果關(guān)閉activity則接下來調(diào)用onDestroy()。

onRestart()

or

onDestroy()

onDestroy()

在activity銷毀前調(diào)用。這是activity接收的最后一個(gè)調(diào)用。這可能發(fā)生在activity結(jié)束(調(diào)用了它的?finish()?方法)或者因?yàn)橄到y(tǒng)需要空間所以臨時(shí)的銷毀了此acitivity的實(shí)例時(shí)。你可以用isFinishing()方法來區(qū)分這兩種情況。

???????? 請注意上表中可被殺死一列。它標(biāo)示了在方法返回后,還沒執(zhí)行activity的其余代碼的任意時(shí)間里,系統(tǒng)是否可以殺死包含此activity的進(jìn)程。三個(gè)方法(onPause()、 onStop()和onDestroy())被標(biāo)記為“是”。onPause()是三個(gè)中的第一個(gè),它也是唯一一個(gè)在進(jìn)程被殺死之前必然會(huì)調(diào)用的方法──onStop() 和 onDestroy() 有可能不被執(zhí)行。因此你應(yīng)該用 onPause() 來將所有持久性數(shù)據(jù)(比如用戶的編輯結(jié)果)寫入存儲(chǔ)之中。

???????? 在可被殺死一列中標(biāo)記為“否”的方法在它們被調(diào)用時(shí)將保護(hù)activity所在的進(jìn)程不會(huì)被殺死。所以只有在onPause()方法返回后到onResume() 方法被調(diào)用時(shí),一個(gè)activity才處于可被殺死的狀態(tài)。在onPause()再次被調(diào)用并返回之前,它不會(huì)被系統(tǒng)殺死。

????如后面一節(jié)進(jìn)程和生命周期所述,即使是在這里技術(shù)上沒有被定義為“可殺死”的activity仍然有可能被系統(tǒng)殺死──但這僅會(huì)發(fā)生在實(shí)在沒有其它方法的極端情況之下。

?

保存activity狀態(tài)(Saving activity state)

???????? 當(dāng)系統(tǒng)而不是用戶自己出于回收內(nèi)存的考慮,關(guān)閉了一個(gè)activity之后。用戶會(huì)期望當(dāng)他再次回到那個(gè)activity的時(shí)候,它仍保持著上次離開時(shí)的樣子。

???????? 為了獲取activity被殺死前的狀態(tài),你應(yīng)該為activity實(shí)現(xiàn)onSaveInstanceState()?方法。Android在activity有可能被銷毀之前(即onPause() 調(diào)用之前)會(huì)調(diào)用此方法。它會(huì)將一個(gè)以名稱-值對方式記錄了activity動(dòng)態(tài)狀態(tài)的Bundle 對象傳遞給該方法。當(dāng)activity再次啟動(dòng)時(shí),這個(gè)Bundle會(huì)傳遞給onCreate()方法和隨著onStart()方法調(diào)用的onRestoreInstanceState(),所以它們兩個(gè)都可以恢復(fù)捕獲的狀態(tài)。

???????? 與onPause()或先前討論的其它方法不同,onSaveInstanceState() 和 onRestoreInstanceState() 并不是生命周期方法。它們并不是總會(huì)被調(diào)用。比如說,Android會(huì)在activity易于被系統(tǒng)銷毀之前調(diào)用 onSaveInstanceState(),但用戶動(dòng)作(比如按下了BACK鍵)造成的銷毀則不調(diào)用。在這種情況下,用戶沒打算再次回到這個(gè)activity,所以沒有保存狀態(tài)的必要。

???????? 因?yàn)閛nSaveInstanceState()不是總被調(diào)用,所以你應(yīng)該只用它來為activity保存一些臨時(shí)的狀態(tài),而不能用來保存持久性數(shù)據(jù)。而是應(yīng)該用onPause()來達(dá)到這個(gè)目的。

?

服務(wù)生命周期(Coordinating activities)

???????? 服務(wù)以兩種方式使用:

l? 它可以啟動(dòng)并運(yùn)行,直至有人停止了它或它自己停止。在這種方式下,它以調(diào)用Context.startService()啟動(dòng),而以調(diào)用Context.stopService()結(jié)束。它可以調(diào)用Service.stopSelf()?或?Service.stopSelfResult()來自己停止。不論調(diào)用了多少次startService()方法,你只需要調(diào)用一次stopService()來停止服務(wù)。

l? 它可以通過自己定義并暴露出來的接口進(jìn)行程序操作??蛻舳私⒁粋€(gè)到服務(wù)對象的連接,并通過那個(gè)連接來調(diào)用服務(wù)。連接以調(diào)用Context.bindService()方法建立,以調(diào)用?Context.unbindService()關(guān)閉。多個(gè)客戶端可以綁定至同一個(gè)服務(wù)。如果服務(wù)此時(shí)還沒有加載,bindService()會(huì)先加載它。

這兩種模式并不是完全分離的。你可以綁定至一個(gè)用 startService()啟動(dòng)的服務(wù)。比如說,一個(gè)后臺(tái)音樂播放服務(wù)可以調(diào)用startService()并傳遞給它一個(gè)包含欲播放的音樂列表的Intent對象來啟動(dòng)。不久,當(dāng)用戶想要對播放器進(jìn)行控制或者查看當(dāng)前播放曲目的詳情時(shí),會(huì)啟用一個(gè)activity,調(diào)用bindService()連接到服務(wù)來完成操作。在這種情況下,直到綁定連接關(guān)閉stopService() 才會(huì)真正停止一個(gè)服務(wù)。

與activity一樣,服務(wù)也有一系列你可以實(shí)現(xiàn)以用于監(jiān)控其狀態(tài)變化的生命周期方法。但相對于activity要少一些,只有三個(gè),而且,它們是public屬性,并非protected:

void onCreate()

void onStart(Intent intent)

void onDestroy()

???????? 倚仗實(shí)現(xiàn)這些方法,你監(jiān)控服務(wù)的兩個(gè)嵌套的生命周期循環(huán):

l? 服務(wù)的完整生命周期始于調(diào)用onCreate()而終于onDestroy()方法返回。如同activity一樣,服務(wù)在onCreate()里面進(jìn)行它自己的初始化,而在onDestroy()里面釋放所有資源。比如說,一個(gè)音樂回放服務(wù)可以在onCreate()中創(chuàng)建播放音樂的線程, 而在onDestroy()中停止這個(gè)線程。

l? 服務(wù)的活躍生命周期始于調(diào)用onStart()。這個(gè)方法用于處理傳遞給startService()的Intent對象。音樂服務(wù)會(huì)打開Intent來探明將要播放哪首音樂,并開始播放。

服務(wù)停止時(shí)沒有相應(yīng)的回調(diào)方法──不存在onStop()方法。

???????? onCreate()和onDestroy()方法在所有服務(wù)中都會(huì)被調(diào)用,無論它們是由Context.startService()還是由Context.bindService()所啟動(dòng)的。而onStart()僅會(huì)被startService()所啟用的服務(wù)調(diào)用。

???????? 如果一個(gè)服務(wù)允許別的進(jìn)程綁定,則它還會(huì)有以下額外的回調(diào)方法以供實(shí)現(xiàn):

IBinder onBind(Intent intent)

boolean onUnbind(Intent intent)

void onRebind(Intent intent)

???????? 傳遞給bindService的Intent的對象也會(huì)傳遞給onBind()回調(diào)方法,而傳遞給unbindService()的Intent對象同樣傳遞給onUnbind()。如果服務(wù)允許綁定,onBind()將返回一個(gè)供客戶端與服務(wù)進(jìn)行交互的通訊渠道。如果有新的客戶端連接至服務(wù),則onUnbind()方法可以要求調(diào)用onRebind()?。

???????? 下圖描繪了服務(wù)的回調(diào)方法。盡管圖中對由startService 和startService方法啟動(dòng)的服務(wù)做了區(qū)分,但要記住,不論一個(gè)服務(wù)是怎么啟動(dòng)的,它都可能允許客戶端的連接,所以任何服務(wù)都可以接受onBind()和onUnbind()調(diào)用。

?

????????

廣播接收器生命周期(Broadcast receiver lifecycle)

???????? 廣播接收器只有一個(gè)回調(diào)方法:

?????????????????? void onReceive(Context curContext, Intent broadcastMsg)

???????? 當(dāng)廣播消息抵達(dá)接收器時(shí),Android調(diào)用它的onReceive()?方法并將包含消息的Intent對象傳遞給它。廣播接收器僅在它執(zhí)行這個(gè)方法時(shí)處于活躍狀態(tài)。當(dāng)onReceive()返回后,它即為失活狀態(tài)。

???????? 擁有一個(gè)活躍狀態(tài)的廣播接收器的進(jìn)程被保護(hù)起來而不會(huì)被殺死。但僅擁有失活狀態(tài)組件的進(jìn)程則會(huì)在其它進(jìn)程需要它所占有的內(nèi)存的時(shí)候隨時(shí)被殺掉。

???????? 這種方式引出了一個(gè)問題:如果響應(yīng)一個(gè)廣播信息需要很長的一段時(shí)間,我們一般會(huì)將其納入一個(gè)衍生的線程中去完成,而不是在主線程內(nèi)完成它,從而保證用戶交互過程的流暢。如果onReceive()衍生了一個(gè)線程并且返回,則包涵新線程在內(nèi)的整個(gè)進(jìn)程都被會(huì)判為失活狀態(tài)(除非進(jìn)程內(nèi)的其它應(yīng)用程序組件仍處于活躍狀態(tài)),于是它就有可能被殺掉。這個(gè)問題的解決方法是令onReceive()啟動(dòng)一個(gè)新服務(wù),并用其完成任務(wù),于是系統(tǒng)就會(huì)知道進(jìn)程中仍然在處理著工作。

???????? 下一節(jié)中,我們會(huì)討論更多進(jìn)程易誤殺的問題。

?

進(jìn)程與生命周期(Processes and lifecycles)

???????? Android系統(tǒng)會(huì)盡可能長的延續(xù)一個(gè)應(yīng)用程序進(jìn)程,但在內(nèi)存過低的時(shí)候,仍然會(huì)不可避免需要移除舊的進(jìn)程。為決定保留或移除一個(gè)進(jìn)程,Android 將每個(gè)進(jìn)程都放入一個(gè)“重要性層次”中,依據(jù)則是它其中運(yùn)行著的組件及其狀態(tài)。重要性最低的進(jìn)程首先被消滅,然后是較低的,依此類推。重要性共分五層,依 據(jù)重要性列表如下:

1.?????????前臺(tái)進(jìn)程是用戶操作所必須的。當(dāng)滿足如下任一條件時(shí),進(jìn)程被認(rèn)為是處于前臺(tái)的:

l? 它運(yùn)行著正在與用戶交互的activity(Activity對象的?onResume()?方法已被調(diào)用)。

l? 一個(gè)正在與用戶交互的activity使用著它提供的一個(gè)服務(wù)。

l? 它包含著一個(gè)正在執(zhí)行生命周期回調(diào)方法(onCreate()、onStart()或onDestroy())的Service對象。

l? 它包含著一個(gè)正在執(zhí)行?onReceive()?方法的BroadcastReceiver對象。

任一時(shí)間下,僅有少數(shù)進(jìn)程會(huì)處于前臺(tái),僅當(dāng)內(nèi)存實(shí)在無法供給它們維持同時(shí)運(yùn)行時(shí)才會(huì)被殺死。一般來說,在這種情況下,設(shè)備已然處于使用虛擬內(nèi)存的狀態(tài),必須要?dú)⑺酪恍┣芭_(tái)進(jìn)程以用戶界面保持響應(yīng)。

2.?????????可視進(jìn)程沒有前臺(tái)組件,但仍可被用戶在屏幕上所見。當(dāng)滿足如下任一條件時(shí),進(jìn)程被認(rèn)為是可視的:

l? 它包含著一個(gè)不在前臺(tái),但仍然為用戶可見的activity(它的onPause()方法被調(diào)用)。這種情況可能出現(xiàn)在以下情況:比如說,前臺(tái)activity是一個(gè)對話框,而之前的activity位于其下并可以看到。

l? 它包含了一個(gè)綁定至一個(gè)可視的activity的服務(wù)。

可視進(jìn)程依然被視為是很重要的,非到不殺死它們便無法維持前臺(tái)進(jìn)程運(yùn)行時(shí),才會(huì)被殺死。

3.?????????服務(wù)進(jìn)程是由?startService()?方法啟動(dòng)的服務(wù),它不會(huì)變成上述兩類。盡管服務(wù)進(jìn)程不會(huì)直接為用戶所見,但它們一般都在做著用戶所關(guān)心的事情(比如在后臺(tái)播放mp3或者從網(wǎng)上下載東西)。所以系統(tǒng)會(huì)盡量維持它們的運(yùn)行,除非系統(tǒng)內(nèi)存不足以維持前臺(tái)進(jìn)程和可視進(jìn)程的運(yùn)行需要。

4.?????????背景進(jìn)程包含目前不為用戶所見的activity(Activity對象的?onStop()?方法已被調(diào)用)。這些進(jìn)程與用戶體驗(yàn)沒有直接的聯(lián)系,可以在任意時(shí)間被殺死以回收內(nèi)存供前臺(tái)進(jìn)程、可視進(jìn)程以及服務(wù)進(jìn)程使用。一般來說,會(huì)有很多背景進(jìn)程 運(yùn)行,所以它們一般存放于一個(gè)LRU(最后使用)列表中以確保最后被用戶使用的activity最后被殺死。如果一個(gè)activity正確的實(shí)現(xiàn)了生命周 期方法,并捕獲了正確的狀態(tài),則殺死它的進(jìn)程對用戶體驗(yàn)不會(huì)有任何不良影響。

5.?????????空進(jìn)程不包含任何活動(dòng)應(yīng)用程序組件。這種進(jìn)程存在的唯一原因是做為緩存以改善組件再次于其中運(yùn)行時(shí)的啟動(dòng)時(shí)間。系統(tǒng)經(jīng)常會(huì)殺死這種進(jìn)程以保持進(jìn)程緩存和系統(tǒng)內(nèi)核緩存之間的平衡。

Android會(huì)依據(jù)進(jìn)程中當(dāng)前活躍組件的重要程度來盡可能高的估量一個(gè)進(jìn)程的級別。比如說,如果一個(gè)進(jìn)程中同時(shí)有一個(gè)服務(wù)和一個(gè)可視的activity,則進(jìn)程會(huì)被判定為可視進(jìn)程,而不是服務(wù)進(jìn)程。

此外,一個(gè)進(jìn)程的級別可能會(huì)由于其它進(jìn)程依賴于它而升高。一個(gè)為其它進(jìn)程提供服務(wù)的進(jìn)程級別永遠(yuǎn)高于使用它服務(wù)的進(jìn)程。比如說,如果A進(jìn)程中的內(nèi)容提供者 為進(jìn)程B中的客戶端提供服務(wù),或進(jìn)程A中的服務(wù)為進(jìn)程B中的組件所綁定,則A進(jìn)程最低也會(huì)被視為與進(jìn)程B擁有同樣的重要性。

為運(yùn)行著一個(gè)服務(wù)的進(jìn)程重要級別總高于一個(gè)背景activity。所以一個(gè)activity以啟動(dòng)一個(gè)服務(wù)的方式啟動(dòng)一個(gè)長時(shí)間運(yùn)行過程比簡單的衍生一個(gè) 線程來進(jìn)行處理要好。尤其是當(dāng)處理過程比activity本身存在時(shí)間要長的情況之下。我們以背景音樂播放和上傳一個(gè)相機(jī)拍攝的圖片至網(wǎng)站上為例。使用服 務(wù)則不論activity發(fā)生何事,都至少可以保證操作擁有“服務(wù)進(jìn)程”的權(quán)限。如上一節(jié)廣播接收器生命周期?所提到的,這也正是廣播接收器使用服務(wù),而不是使用線程來處理耗時(shí)任務(wù)的原因。

總結(jié)

以上是生活随笔為你收集整理的Application Fundamentals的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。