大多數(shù)操作系統(tǒng),在應(yīng)用程序所寄存的可執(zhí)行程序映像(如Windows系統(tǒng)里的.exe)、它所運(yùn)行的進(jìn)程以及和用戶交互的圖標(biāo)和應(yīng)用之間有一種嚴(yán)格的1對(duì)1關(guān)系。在Android系統(tǒng)里,這些關(guān)聯(lián)要松散得多。并且重要的是要理解各種概念怎么樣組成整體。

由于Android應(yīng)用固有的靈活性,當(dāng)實(shí)現(xiàn)這些不同方面的時(shí)候有一些基本術(shù)語(yǔ)需要加以理解:

一個(gè)Android包 (.apk)文件,其中包含一個(gè)應(yīng)用程序的代碼和資源。這是應(yīng)用程序分發(fā)和下載的文件,用戶用來(lái)安裝該應(yīng)用程序在他們的設(shè)備上。
一個(gè)任務(wù)一般而言是指用戶視為的一個(gè)可啟動(dòng)應(yīng)用程序:通常任務(wù)在桌面(home screen)有一個(gè)可訪問(wèn)的圖標(biāo),且可以被切換到前臺(tái)。
一個(gè)進(jìn)程是一個(gè)運(yùn)行著應(yīng)用程序代碼的底層核心過(guò)程。通常所有.apk里的代碼運(yùn)行在一個(gè)專有的進(jìn)程里。不過(guò),進(jìn)程標(biāo)記也可以用來(lái)限定代碼運(yùn)行位置,或者為整個(gè).apk或者為個(gè)別的活動(dòng)activity,接收者receiver,服務(wù)或提供者provider,組件。
任務(wù)

這里的一個(gè)關(guān)鍵點(diǎn)是:當(dāng)用戶看到一個(gè)“應(yīng)用”時(shí),他們實(shí)際上在和任務(wù)打交道。如果您剛剛創(chuàng)建一個(gè)包含若干活動(dòng)的.apk,其中之一是頂層入口點(diǎn)(通 過(guò)動(dòng)作android.intent.action.MAIN的意圖過(guò)濾器intent-filter和類別 android.intent.category.LAUNCHER),那么這事實(shí)上將為您的.apk創(chuàng)建一個(gè)任務(wù),并且您從那兒起動(dòng)的任何活動(dòng)都將作為 那個(gè)任務(wù)的一部分運(yùn)行。

一個(gè)任務(wù),那么,從用戶的角度來(lái)看是您的應(yīng)用程序;而從應(yīng)用程序開(kāi)發(fā)者的角度來(lái)看,它是一個(gè)或多個(gè)用戶在那個(gè)任務(wù)中已經(jīng)經(jīng)歷過(guò)且未關(guān)閉的活動(dòng),或者 說(shuō)是一個(gè)活動(dòng)棧。一個(gè)新的任務(wù)通過(guò)以Intent.FLAG_ACTIVITY_NEW_TASK標(biāo)志起動(dòng)一個(gè)活動(dòng)意圖來(lái)創(chuàng)建;這一意圖將被用來(lái)作為任務(wù) 的根意圖,定義任務(wù)是什么。任何不以這個(gè)標(biāo)志起動(dòng)的活動(dòng)將和起動(dòng)它的活動(dòng)在相同的任務(wù)中運(yùn)行(除非該活動(dòng)已請(qǐng)求特別啟動(dòng)模式,稍后會(huì)討論)。任務(wù)可以被重 新安排:如果您使用FLAG_ACTIVITY_NEW_TASK標(biāo)志但已經(jīng)有一個(gè)任務(wù)以這個(gè)意圖運(yùn)行,則當(dāng)前任務(wù)的活動(dòng)棧將被切換到前臺(tái)而不是開(kāi)始一個(gè) 新的任務(wù)。

FLAG_ACTIVITY_NEW_TASK必須謹(jǐn)慎使用:使用它意味著,在用戶看來(lái),一個(gè)新的應(yīng)用程序由此起動(dòng)。如果這不是你所期望的行為,你 就不該去創(chuàng)建一個(gè)新的任務(wù)。另外,僅在用戶可以從桌面返回到他原來(lái)的地方和以一個(gè)新任務(wù)啟動(dòng)相同意圖的情況下,你才應(yīng)該使用新的任務(wù)標(biāo)記。否則,如果用戶 在你已經(jīng)啟動(dòng)的任務(wù)里按桌面(HOME)鍵,而不是返回(BACK)鍵,你的任務(wù)及其活動(dòng)將被放置到桌面后面,沒(méi)有辦法再切換回去。

任務(wù)共用性Affinity

在某些情況下,Android需要知道一個(gè)活動(dòng)屬于哪個(gè)任務(wù)即使它沒(méi)有被啟動(dòng)到一個(gè)具體的任務(wù)里。這是通過(guò)任務(wù)共用性(Affinities)完成 的。任務(wù)共用性(Affinities)為這個(gè)運(yùn)行一個(gè)或多個(gè)活動(dòng)的任務(wù)提供了一個(gè)獨(dú)特的靜態(tài)名稱,默認(rèn)的一個(gè)活動(dòng)的任務(wù)共用性(Affinity)是實(shí) 現(xiàn)了該活動(dòng)的.apk包的名字。這提供了預(yù)期的標(biāo)準(zhǔn)特性,即所有在一個(gè)特定的.apk包里的活動(dòng)是單個(gè)用戶應(yīng)用程序的一部分。

當(dāng)開(kāi)始一個(gè)沒(méi)有Intent.FLAG_ACTIVITY_NEW_TASK標(biāo)志的活動(dòng)時(shí),任務(wù)共用性affinities不會(huì)影響將會(huì)運(yùn)行該新活 動(dòng)的任務(wù):它總是運(yùn)行在啟動(dòng)它的任務(wù)里。但是,如果使用了NEW_TASK標(biāo)志,那么共用性(affinity)將被用來(lái)判斷是否已經(jīng)存在一個(gè)有相同共用 性(affinity)的任務(wù)。如果是這樣,這項(xiàng)任務(wù)將被切換到前面而新的活動(dòng)會(huì)啟動(dòng)于這個(gè)任務(wù)的頂層。

 

這種特性在您必須使用NEW_TASK標(biāo)志的情況下最有用,尤其是從狀態(tài)欄通知或桌面快捷方式啟動(dòng)活動(dòng)時(shí)。結(jié)果是,當(dāng)用戶用這種方式啟動(dòng)您的應(yīng)用程序時(shí),它的當(dāng)前任務(wù)將被切換到前臺(tái),而且想要查看的活動(dòng)被放在最上面。

你可以在程序清單(Manifest)文件的應(yīng)用程序application標(biāo)簽中為.apk包中所有的活動(dòng)分配你自己的任務(wù)共用性Affinites,或者在活動(dòng)標(biāo)記中為各個(gè)活動(dòng)進(jìn)行分配。一些說(shuō)明其如何使用的例子如下:

如果您的.apk包含多個(gè)用戶可以啟動(dòng)的高層應(yīng)用程序,那么您可能需要對(duì)用戶看到的每個(gè)活動(dòng)指定不同的affinities。一個(gè)不錯(cuò)的命名慣例是 以附加一個(gè)以冒號(hào)分隔的字符串來(lái)擴(kuò)展您的.apk包名。例如,“ com.android.contacts ”.apk可以有affinities:“com.android.contacts:Dialer”和“ com.android.contacts:ContactsList”。
如果您正在替換一個(gè)通知,快捷方式,或其他可以從外部發(fā)起的應(yīng)用程序 的“內(nèi)部”活動(dòng),你可能需要明確設(shè)定您替代活動(dòng)的taskAffinity和您準(zhǔn)備替代的應(yīng)用程序一樣。例如,如果您想替換contacts詳細(xì)信息視圖 (用戶可以創(chuàng)建并調(diào)用快捷方式),你得把taskAffinity設(shè)置成“com.android.contacts”。
啟動(dòng)模式和啟動(dòng)標(biāo)志

您控制活動(dòng)和任務(wù)交互的主要途徑是通過(guò)活動(dòng)的launchMode 屬性和意圖相關(guān)的標(biāo)志flags。這兩個(gè)參數(shù)可以以各種方式合作來(lái)控制活動(dòng)啟動(dòng)的結(jié)果,正如它們相關(guān)文檔中描述的那樣。在這里,我們將看看一些常見(jiàn)的用例和參數(shù)組合。

你將使用的最常見(jiàn)的啟動(dòng)模式(除了默認(rèn)的standard模式)是singleTop。這并不影響任務(wù);它只是避免多次在一個(gè)堆棧頂部起動(dòng)同一活動(dòng)。

singleTask啟動(dòng)模式對(duì)任務(wù)有重大的影響:它使活動(dòng)始終是開(kāi)始于一項(xiàng)新的任務(wù)(或其現(xiàn)有的任務(wù)被帶到前臺(tái)) 。使用這種模式需要謹(jǐn)慎對(duì)待你如何與系統(tǒng)其他部分進(jìn)行交互,因?yàn)檫@影響到這個(gè)活動(dòng)中的每一個(gè)路徑。它應(yīng)當(dāng)僅在活動(dòng)處于應(yīng)用程序前臺(tái)時(shí)使用(也就是支持 MAIN動(dòng)作和LAUNCHER類別)。

singleInstance啟動(dòng)模式更是專業(yè),并應(yīng)僅用于整個(gè)就是被實(shí)現(xiàn)為一個(gè)活動(dòng)的應(yīng)用程序中。

有一種你會(huì)經(jīng)常遇到的情況是當(dāng)另一個(gè)實(shí)體(如SearchManager 或NotificationManager)開(kāi)始您的一個(gè)活動(dòng)。在這種情況下,必須使用Intent.FLAG_ACTIVITY_NEW_TASK 標(biāo)簽,因?yàn)樵擁?xiàng)活動(dòng)是在任務(wù)之外起動(dòng)的(而且應(yīng)用/任務(wù)可能根本不存在)。正如前面所述,這種情況下的標(biāo)準(zhǔn)行為是把匹配新活動(dòng)affinity的任務(wù)帶到 前臺(tái)和在此之上起動(dòng)新的活動(dòng)。不過(guò),也有其他您可以實(shí)施的行為類型。

其中一種常見(jiàn)的做法是,還可以使用Intent.FLAG_ACTIVITY_CLEAR_TOP 國(guó)旗與NEW_TASK 。通過(guò)這樣做,如果你的任務(wù)已經(jīng)運(yùn)行,那么將提請(qǐng)前景,所有的活動(dòng),其堆棧清除除根系活力和根系活力的onNewIntent (意圖) 所謂的意圖正在開(kāi)始。請(qǐng)注意,該活動(dòng)還常常使用singleTop 或singleTask 發(fā)射模式時(shí),使用這種方法,因此,目前的情況是由于新的意圖而不需要將它摧毀,一個(gè)新的實(shí)例開(kāi)始。

一種通常的辦法是和NEW_TASK聯(lián)合起來(lái)使用Intent.FLAG_ACTIVITY_CLEAR_TOP標(biāo)志。這樣,如果您的任務(wù)已經(jīng)運(yùn) 行,那么它將會(huì)被帶到前臺(tái),除根活動(dòng)外其它所有堆棧中的活動(dòng)都被清除,而且這個(gè)根活動(dòng)的方法onNewIntent(Intent)會(huì)在該意圖起動(dòng)時(shí)被調(diào) 用。注意這個(gè)活動(dòng)使用這個(gè)方法時(shí)經(jīng)常使用singleTop或者singleTask起動(dòng)模式,這樣當(dāng)前實(shí)例被賦予新的意圖而不是需要銷毀它然后重新起動(dòng) 一個(gè)新的實(shí)例。

您能采取的另外的方法是設(shè)置通知活動(dòng)的任務(wù)affinity為空字符串“”(表示沒(méi)有affinity),并設(shè)置 finishOnBackground屬性。這種方法是有用的如果你希望這個(gè)通知把用戶帶到一個(gè)單獨(dú)的描述它的活動(dòng)中,而不是返回到應(yīng)用程序的任務(wù)。通過(guò) 指定這個(gè)屬性,該活動(dòng)將被結(jié)束不管用戶通過(guò)BACK還是HOME離開(kāi)它;如果這個(gè)屬性沒(méi)有指定,按首頁(yè)將導(dǎo)致這個(gè)活動(dòng)及其任務(wù)仍保留在系統(tǒng)里,且可能沒(méi)有 辦法返回它。

請(qǐng)務(wù)必閱讀關(guān)于launchMode屬性和Intent標(biāo)志的文檔以獲取這些選項(xiàng)的詳細(xì)說(shuō)明。

 

 

進(jìn)程

在Android里,進(jìn)程完全是應(yīng)用的實(shí)現(xiàn)細(xì)節(jié),而不是用戶通常了解的那樣。其主要用途就是:

通過(guò)安置不受信任的或不穩(wěn)定的代碼到另一個(gè)進(jìn)程來(lái)提高穩(wěn)定性或安全性。
通過(guò)在同一進(jìn)程里運(yùn)行多個(gè).apks的代碼來(lái)減少開(kāi)銷。
通過(guò)把重量級(jí)代碼放在單獨(dú)的進(jìn)程中來(lái)幫助系統(tǒng)管理資源,該進(jìn)程可以在不影響應(yīng)用程序其他部分的情況下被終止。
正如前面所述,這個(gè)進(jìn)程屬性用來(lái)控制運(yùn)行著特定應(yīng)用程序組件的進(jìn)程,注意,此屬性不能用于違反系統(tǒng)安全性:如果有兩個(gè)不共享相同用戶ID的.apks嘗試運(yùn)行在同一進(jìn)程中,這將不會(huì)被允許,相反會(huì)為它們每一個(gè)創(chuàng)建不同的進(jìn)程。

參見(jiàn)安全 文檔以獲取更多關(guān)于安全限制方面的信息。

Android相關(guān)內(nèi)容:


 

線程

每個(gè)進(jìn)程包含一個(gè)或多個(gè)線程。多數(shù)情況下,Android避免在進(jìn)程里創(chuàng)建額外的線程,以保持應(yīng)用程序單線程,除非它創(chuàng)建自己的線程。一個(gè)重要的結(jié) 果就是所有對(duì)活動(dòng)Activity,廣播接收器BroadcastReceiver以及服務(wù)Service實(shí)例的調(diào)用都是由這個(gè)進(jìn)程的主線程創(chuàng)建的。

注意新的線程并不會(huì)為每個(gè)活動(dòng),廣播接收器,服務(wù)或者內(nèi)容提供器(ContentProvider)實(shí)例而創(chuàng)建:這些應(yīng)用程序的組件在進(jìn)程里被實(shí)例 化(除非另有說(shuō)明,都在同一個(gè)進(jìn)程處理),實(shí)際上是進(jìn)程的主線程。這說(shuō)明當(dāng)被系統(tǒng)調(diào)用時(shí)沒(méi)有哪個(gè)組件(包括服務(wù))會(huì)進(jìn)行遠(yuǎn)程或者阻塞操作(就像網(wǎng)絡(luò)調(diào)用或 者計(jì)算循環(huán)),因?yàn)檫@將阻止進(jìn)程中的所有其他組件。你可以使用標(biāo)準(zhǔn)的線程類Thread或者Android的HandlerThread便捷類去對(duì)其它線 程執(zhí)行遠(yuǎn)程操作。

這里有一些關(guān)于這個(gè)線程規(guī)則的重要的例外:

  ? 對(duì)IBinder或者IBinder實(shí)現(xiàn)的接口的調(diào)用由調(diào)用線程或本地進(jìn)程的線程池(如果該呼叫來(lái)自其他進(jìn)程)分發(fā),而不是它們的進(jìn)程的主線程。特殊情況 下,一個(gè)服務(wù)的IBinder可以這樣調(diào)用。(盡管調(diào)用服務(wù)里的方法已經(jīng)在主線程里完成。)這意味著IBinder接口的實(shí)現(xiàn)必須要有一種線程安全的方 法,這樣任意線程才能同時(shí)訪問(wèn)它。
  ? 對(duì)ContentProvider主要方法的調(diào)用由調(diào)用線程或者主線程分發(fā),如同IBinder一樣。被指定的方法在內(nèi)容提供器的類里有記錄。這意味著實(shí)現(xiàn)這些方法必須要有一種線程安全的模式,這樣任意其它線程可以同時(shí)訪問(wèn)它。
  ? 視圖及其子類中的調(diào)用由正在運(yùn)行著視圖的線程產(chǎn)生。通常情況下,這會(huì)被作為進(jìn)程的主線程,如果你創(chuàng)建一個(gè)線程并顯示一個(gè)窗口,那么繼承的窗口視圖將從那個(gè)線程里啟動(dòng)。