Android開發指南-框架主題-基礎知識

應用程序基礎
關鍵類
Activity
Service
BroadcastReceiver
ContentProvider
Intent
Android應用程序使用Java作爲開發語言。aapt工具把編譯後的Java代碼連同其它應用程序須要的數據和資源文件一塊兒打包到一個Android包文件中,這個文件使用.apk作爲擴展名,它是分發應用程序並安裝到移動設備的媒介,用戶只需下載並安裝此文件到他們的設備。單一.apk文件中的全部代碼被認爲是一個應用程序。android

從不少方面來看,每一個Android應用程序都存在於它本身的世界之中:數據庫

默認狀況下,每一個應用程序均運行於它本身的Linux進程中。當應用程序中的任意代碼開始執行時,Android啓動一個進程,而當再也不須要此進程而其它應用程序又須要系統資源時,則關閉這個進程。
每一個進程都運行於本身的Java虛擬機(VM)中。因此應用程序代碼實際上與其它應用程序的代碼是隔絕的。
默認狀況下,每一個應用程序均被賦予一個惟一的Linux用戶ID,並加以權限設置,使得應用程序的文件僅對這個用戶、這個應用程序可見。固然,也有其它的方法使得這些文件一樣能爲別的應用程序所訪問。
使兩個應用程序共有同一個用戶ID是可行的,這種狀況下他們能夠看到彼此的文件。從系統資源維護的角度來看,擁有同一個ID的應用程序也將在運行時使用同一個Linux進程,以及同一個虛擬機。瀏覽器

應用程序組件
Android的核心功能之一就是一個應用程序可使用其它應用程序的元素(若是那個應用程序容許的話)。好比說,若是你的應用程序須要一個圖片捲動列表,而另外一個應用程序已經開發了一個合用的而又容許別人使用的話,你能夠直接調用那個捲動列表來完成工做,而不用本身再開發一個。你的應用程序並無吸納或連接其它應用程序的代碼,它只是在有需求的時候啓動了其它應用程序的那個功能部分。緩存

爲達到這個目的,系統必須在一個應用程序的一部分被須要時啓動這個應用程序,並將那個部分的Java對象實例化。與在其它系統上的應用程序不一樣,Android應用程序沒有爲應用準備一個單獨的程序入口(好比說,沒有main()方法), 而是爲系統依照需求實例化提供了基本的組件。共有四種組件類型:安全

Activity網絡

Activity是爲用戶操做而展現的可視化用戶界面。好比說,一個activity能夠展現一個菜單項列表供用戶選擇,或者顯示一些包含說明的照片。一個短消息應用程序能夠包括一個用於顯示作爲發送對象的聯繫人的列表的activity,一個給選定的聯繫人寫短信的activity以及翻閱之前的短信和改變設置的activity。儘管它們一塊兒組成了一個內聚的用戶界面,但其中每一個activity都與其它的保持獨立。每一個都是以Activity類爲基類的子類實現。多線程

一個應用程序能夠只有一個activity,或者,如剛纔提到的短信應用程序那樣,包含不少個。每一個activity的做用,以及其數目,天然取決於應用程序及其設計。通常狀況下,總有一個應用程序被標記爲用戶在應用程序啓動的時候第一個看到的。從一個activity轉向另外一個的方式是靠當前的activity啓動下一個。app

每一個activity都被給予一個默認的窗口以進行繪製。通常狀況下,這個窗口是滿屏的,但它也能夠是一個小的位於其它窗口之上的浮動窗口。一個activity也可使用超過一個的窗口──好比,在activity運行過程當中彈出的一個供用戶反應的小對話框,或是當用戶選擇了屏幕上特定項目後顯示的必要信息。異步

窗口顯示的可視內容是由一系列視圖構成的,這些視圖均繼承自 View 基類。每一個視圖均控制着窗口中一塊特定的矩形空間。父級視圖包含並組織它子視圖的佈局。葉節點視圖(位於視圖層次最底端)在它們控制的矩形中進行繪製,並對用戶對其直接操做作出響應。因此,視圖是activity與用戶進行交互的界面。好比說,視圖能夠顯示一個小圖片,並在用戶指點它的時候產生動做。Android有不少既定的視圖供用戶直接使用,包括按鈕、文本域、卷軸、菜單項、複選框等等。ide

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

服務

服務沒有可視化的用戶界面,而是在一段時間內在後臺運行。好比說,一個服務能夠在用戶作其它事情的時候在後臺播放背景音樂、從網絡上獲取一些數據或者計算一些東西並提供給須要這個運算結果的activity使用。每一個服務都繼承自Service基類。

一個媒體播放器播放播放列表中的曲目是一個不錯的例子。播放器應用程序可能有一個或多個activity來給用戶選擇歌曲並進行播放。然而,音樂播放這個任務自己不該該爲任何activity所處理,由於用戶指望在他們離開播放器應用程序而開始作別的事情時,音樂仍在繼續播放。爲達到這個目的,媒體播放器activity應該啓用一個運行於後臺的服務。而系統將在這個activity再也不顯示於屏幕以後,仍維持音樂播放服務的運行。

你能夠鏈接至(綁定)一個正在運行的服務(若是服務沒有運行,則啓動之)。鏈接以後,你能夠經過那個服務暴露出來的接口與服務進行通信。對於音樂服務來講,這個接口能夠容許用戶暫停、回退、中止以及從新開始播放。

如同activity和其它組件同樣,服務運行於應用程序進程的主線程內。因此它不會對其它組件或用戶界面有任何干擾,它們通常會派生一個新線程來進行一些耗時任務(好比音樂回放)。參見下述 進程和線程 。

廣播接收器

廣播接收器是一個專一於接收廣播通知信息,並作出對應處理的組件。不少廣播是源自於系統代碼的──好比,通知時區改變、電池電量低、拍攝了一張照片或者用戶改變了語言選項。應用程序也能夠進行廣播──好比說,通知其它應用程序一些數據下載完成並處於可用狀態。


應用程序能夠擁有任意數量的廣播接收器以對全部它感興趣的通知信息予以響應。全部的接收器均繼承自BroadcastReceiver基類。
廣播接收器沒有用戶界面。然而,它們能夠啓動一個activity來響應它們收到的信息,或者用NotificationManager來通知用戶。通知能夠用不少種方式來吸引用戶的注意力──閃動背燈、震動、播放聲音等等。通常來講是在狀態欄上放一個持久的圖標,用戶能夠打開它並獲取消息。

內容提供者

內容提供者將一些特定的應用程序數據供給其它應用程序使用。數據能夠存儲於文件系統、SQLite數據庫或其它方式。內容提供者繼承於ContentProvider 基類,爲其它應用程序取用和存儲它管理的數據實現了一套標準方法。然而,應用程序並不直接調用這些方法,而是使用一個 ContentResolver 對象,調用它的方法做爲替代。ContentResolver能夠與任意內容提供者進行會話,與其合做來對全部相關交互通信進行管理。

參閱獨立的內容提供者章節得到更多關於使用內容提供者的內容。

每當出現一個須要被特定組件處理的請求時,Android會確保那個組件的應用程序進程處於運行狀態,或在必要的時候啓動它。並確保那個相應組件的實例的存在,必要時會建立那個實例。

激活組件:intent
當接收到ContentResolver發出的請求後,內容提供者被激活。而其它三種組件──activity、服務和廣播接收器被一種叫作intent的異步消息所激活。intent是一個保存着消息內容的Intent對象。對於activity和服務來講,它指明瞭請求的操做名稱以及做爲操做對象的數據的URI和其它一些信息。好比說,它能夠承載對一個activity的請求,讓它爲用戶顯示一張圖片,或者讓用戶編輯一些文本。而對於廣播接收器而言,Intent對象指明瞭聲明的行爲。好比,它能夠對全部感興趣的對象聲明照相按鈕被按下。

對於每種組件來講,激活的方法是不一樣的:

經過傳遞一個Intent對象至 Context.startActivity()或Activity.startActivityForResult()以載入(或指定新工做給)一個activity。相應的activity能夠經過調用 getIntent() 方法來查看激活它的intent。Android經過調用activity的onNewIntent()方法來傳遞給它繼發的intent。
一個activity常常啓動了下一個。若是它指望它所啓動的那個activity返回一個結果,它會以調用startActivityForResult()來取代startActivity()。好比說,若是它啓動了另一個activity以使用戶挑選一張照片,它也許想知道哪張照片被選中了。結果將會被封裝在一個Intent對象中,並傳遞給發出調用的activity的onActivityResult() 方法。
經過傳遞一個Intent對象至Context.startService()將啓動一個服務(或給予正在運行的服務以一個新的指令)。Android調用服務的 onStart()方法並將Intent對象傳遞給它。
與此相似,一個Intent能夠被調用組件傳遞給 Context.bindService()以獲取一個正在運行的目標服務的鏈接。這個服務會經由onBind() 方法的調用獲取這個Intent對象(若是服務還沒有啓動,bindService()會先啓動它)。好比說,一個activity能夠鏈接至前述的音樂回放服務,並提供給用戶一個可操做的(用戶界面)以對回放進行控制。這個activity能夠調用 bindService() 來創建鏈接,而後調用服務中定義的對象來影響回放。
後面一節:遠程方法調用將更詳細的闡明如何綁定至服務。
應用程序能夠憑藉將Intent對象傳遞給 Context.sendBroadcast() ,Context.sendOrderedBroadcast(), 以及Context.sendStickyBroadcast()和其它相似方法來產生一個廣播。Android會調用全部對此廣播有興趣的廣播接收器的 onReceive()方法,將intent傳遞給它們。
欲瞭解更多intent消息的信息,請參閱獨立章節 Intent和Intent濾過器。

關閉組件
內容提供者僅在響應ContentResolver提出請求的時候激活。而一個廣播接收器僅在響應廣播信息的時候激活。因此,沒有必要去顯式的關閉這些組件。

而activity則不一樣,它提供了用戶界面,並與用戶進行會話。因此只要會話依然持續,哪怕對話過程暫時停頓,它都會一直保持激活狀態。與此類似,服務也會在很長一段時間內保持運行。因此Android爲關閉activity和服務提供了一系列的方法。

能夠經過調用它的finish()方法來關閉一個activity。一個activity能夠經過調用另一個activity(它用startActivityForResult() 啓動的)的finishActivity()方法來關閉它。
服務能夠經過調用它的stopSelf()方法來中止,或者調用 Context.stopService()。
系統也會在組件再也不被使用的時候或者Android須要爲活動組件聲明更多內存的時候關閉它。後面的 組件的生命週期一節,將對這種可能及附屬狀況進行更詳細的討論。

manifest文件
當Android啓動一個應用程序組件以前,它必須知道那個組件是存在的。因此,應用程序會在一個manifest文件中聲明它的組件,這個文件會被打包到Android包中。這個.apk文件還將涵括應用程序的代碼、文件以及其它資源。

這個manifest文件以XML做爲結構格式,並且對於全部應用程序,都叫作AndroidManifest.xml。爲聲明一個應用程序組件,它還會作不少額外工做,好比指明應用程序所需連接到的庫的名稱(除了默認的Android庫以外)以及聲明應用程序指望得到的各類權限。

但manifest文件的主要功能仍然是向Android聲明應用程序的組件。舉例說明,一個activity能夠以下聲明:

                            . . .    元素的name屬性指定了實現了這個activity的 Activity的子類。icon和label屬性指向了包含展現給用戶的此activity的圖標和標籤的資源文件。

其它組件也以相似的方法聲明── 元素用於聲明服務, 元素用於聲明廣播接收器,而 元素用於聲明內容提供者。 manifest文件中未進行聲明的activity、服務以及內容提供者將不爲系統所見,從而也就不會被運行。然而,廣播接收器既能夠在manifest文件中聲明,也能夠在代碼中進行動態的建立,並以調用Context.registerReceiver()的方式註冊至系統。

欲更多瞭解如何爲你的應用程序構建manifest文件,請參閱AndroidManifest.xml文件一章。

Intent過濾器
Intent對象能夠被顯式的指定目標組件。若是進行了這種指定,Android會找到這個組件(依據manifest文件中的聲明)並激活它。但若是Intent沒有進行顯式的指定,Android就必須爲它找到對於intent來講最合適的組件。這個過程是經過比較Intent對象和全部可能對象的intent過濾器完成的。組件的intent過濾器會告知Android它所能處理的intent類型。如同其它相對於組件很重要的信息同樣,這些是在manifest文件中進行聲明的。這裏是上面實例的一個擴展,其中加入了針對activity的兩個intent過濾器聲明:

                                                                                                                                                            . . .    示例中的第一個過濾器──action 「android.intent.action.MAIN」和類別「android.intent.category.LAUNCHER」的組合──是一般具備的。它標明瞭這個activity將在應用程序加載器中顯示,就是用戶在設備上看到的可供加載的應用程序列表。換句話說,這個activity是應用程序的入口,是用戶選擇運行這個應用程序後所見到的第一個activity。

第二個過濾器聲明瞭這個activity能被賦予一種特定類型的數據。

組件能夠擁有任意數量的intent過濾器,每一個都會聲明一系列不一樣的能力。若是它沒有包含任何過濾器,它將只能被顯式聲明瞭目標組件名稱的intent激活。

對於在代碼中建立並註冊的廣播接收器來講,intent過濾器將被直接以 IntentFilter對象實例化。其它過濾器則在manifest文件中設置。

欲得到更多intent過濾器的信息,請參閱獨立章節: Intent和Intent過濾器。

Activity和任務
如前所述,一個activity能夠啓動另一個,甚至包括與它不處於同一應用程序之中的。舉個例子說,假設你想讓用戶看到某個地方的街道地圖。而已經存在一個具備此功能的activity了,那麼你的activity所須要作的工做就是把請求信息放到一個Intent對象裏面,並把它傳遞給startActivity()。因而地圖瀏覽器就會顯示那個地圖。而當用戶按下BACK鍵的時候,你的activity又會再一次的顯示在屏幕上。

對於用戶來講,這看起來就像是地圖瀏覽器是你activity所在的應用程序中的一個組成部分,其實它是在另一個應用程序中定義,並運行在那個應用程序的進程之中的。Android將這兩個activity放在同一個任務中來維持一個完整的用戶體驗。簡單的說,任務就是用戶所體驗到的「應用程序」。它是安排在一個堆棧中的一組相關的activity。堆棧中的根activity就是啓動了這整個任務的那個──通常狀況下,它就是用戶在應用程序加載器中所選擇的。而堆棧最上方的activity則是當前運行的──用戶直接對其進行操做的。當一個activity啓動另一個的時候,新的activity就被壓入堆棧,併成爲當前運行的activity。而前一個activity仍保持在堆棧之中。當用戶按下BACK鍵的時候,當前activity出棧,而前一個恢復爲當前運行的activity。

堆棧中保存的實際上是對象,因此若是發生了諸如須要多個地圖瀏覽器的狀況,就會使得一個任務中出現多個同一Activity子類的實例同時存在,堆棧會爲每一個實例單獨開闢一個入口。堆棧中的Activity永遠不會重排,只會壓入或彈出。

任務其實就是activity的堆棧,而不是manifest文件中的一個類或者元素。因此你沒法撇開activity而爲一個任務設置一個值。而事實上整個任務使用的值是在根activity中設置的。好比說,下一節咱們會談及「任務的affinity」,從affinity中讀出的值將會設置到任務的根activity之中。

任務中的全部activity是做爲一個總體進行移動的。整個的任務(即activity堆棧)能夠移到前臺,或退至後臺。舉個例子說,好比當前任務在堆棧中存有四個activity──三個在當前activity之下。當用戶按下HOME鍵的時候,回到了應用程序加載器,而後選擇了一個新的應用程序(也就是一個新任務)。則當前任務遁入後臺,而新任務的根activity顯示出來。而後,過了一小會兒,用戶再次回到了應用程序加載器而又選擇了前一個應用程序(上一個任務)。因而那個任務,帶着它堆棧中全部的四個activity,再一次的到了前臺。當用戶按下BACK鍵的時候,屏幕不會顯示出用戶剛纔離開的activity(上一個任務的根activity)。取而代之,當前任務的堆棧中最上面的activity被彈出,而同一任務中的上一個activity顯示了出來。

上述的種種便是activity和任務的默認行爲模式。可是有一些方法能夠改變全部這一切。activity和任務的聯繫、任務中activity的行爲方式都被啓動那個activity的Intent對象中設置的一系列標記和manifest文件中那個activity中的 元素的系列屬性之間的交互所控制。不管是請求發出者和迴應者在這裏都擁有話語權。

咱們剛纔所說的這些關鍵Intent標記以下:

FLAG_ACTIVITY_NEW_TASK
FLAG_ACTIVITY_CLEAR_TOP
FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
FLAG_ACTIVITY_SINGLE_TOP

而關鍵的 屬性是:

taskAffinity
launchMode
allowTaskReparenting
clearTaskOnLaunch
alwaysRetainTaskState
finishOnTaskLaunch

接下來的一節會描述這些標記以及屬性的做用,它們是如何互相影響的,以及控制它們的使用時必須考慮到的因素。

Affinity(吸引力)和新任務
默認狀況下,一個應用程序中的activity相互之間會有一種Affinity──也就是說,它們首選都歸屬於一個任務。然而,能夠在 元素中把每一個activity的taskAffinity屬性設置爲一個獨立的affinity。因而在不一樣的應用程序中定義的activity能夠享有同一個affinity,或者在同一個應用程序中定義的activity有着不一樣的affinity。affinity在兩種狀況下生效:當加載activity的Intent對象包含了FLAG_ACTIVITY_NEW_TASK 標記,或者當activity的allowTaskReparenting屬性設置爲「true」。

FLAG_ACTIVITY_NEW_TASK標記

如前所述,在默認狀況下,一個新activity被另一個調用了startActivity()方法的activity載入了任務之中。並壓入了調用者所在的堆棧。然而,若是傳遞給startActivity()的Intent對象包含了FLAG_ACTIVITY_NEW_TASK標記,系統會爲新activity安排另一個任務。通常狀況下,如同標記所暗示的那樣,這會是一個新任務。然而,這並非必然的。若是已經存在了一個與新activity有着一樣affinity的任務,則activity會載入那個任務之中。若是沒有,則啓用新任務。

allowTaskReparenting 屬性

若是一個activity將allowTaskReparenting屬性設置爲「true」。它就能夠從初始的任務中轉移到與其擁有同一個affinity並轉向前臺的任務之中。好比說,一個旅行應用程序中包含的預報所選城市的天氣狀況的activity。它與這個應用程序中其它的activity擁有一樣的affinity(默認的affinity)並且容許重定父級。你的另外一個activity啓動了天氣預報,因而它就會與這個activity共處與同一任務之中。然而,當那個旅行應用程序再次回到前臺的時候,這個天氣預報activity就會被再次安排到原先的任務之中並顯示出來。

若是在用戶的角度看來,一個.apk文件中包含了多於一個的「應用程序」,你可能會想要爲它們所轄的activity安排不同的affinity。

加載模式
元素的launchMode屬性能夠設置四種不一樣的加載模式:

"standard" (默認值)
"singleTop"
"singleTask"
"singleInstance"

這些模式之間的差別主要體如今四個方面:

哪一個任務會把持對intent作出響應的activity。對「standard」和「singleTop」模式而言,是產生intent(並調用 startActivity())的任務──除非Intent對象包含FLAG_ACTIVITY_NEW_TASK標記。而在這種狀況下,如同上面Affinitie和新任務一節所述,會是另一個任務。
相反,對「singleTask」和「singleInstance」模式而言,activity老是位於任務的根部。正是它們定義了一個任務,因此它們毫不會被載入到其它任務之中。

activity是否能夠存在多個實例。一個「standard」或「singleTop」的activity能夠被屢次初始化。它們能夠歸屬於多個任務,而一個任務也能夠擁有同一activity的多個實例。

相反,對「singleTask」和「singleInstance」的activity被限定於只能有一個實例。由於這些activity都是任務的起源,這種限制意味着在一個設備中同一時間只容許存在一個任務的實例。

在實例所在的任務中是否會有別的activity。一個「singleInstance」模式的activity將會是它所在的任務中惟一的activity。若是它啓動了別的activity,那個activity將會依據它本身的加載模式加載到其它的任務中去──如同在intent中設置了FLAG_ACTIVITY_NEW_TASK 標記同樣的效果。在其它方面,「singleInstance」模式的效果與「singleTask」是同樣的。

剩下的三種模式容許一個任務中出現多個activity。「singleTask」模式的activity將是任務的根activity,但它能夠啓動別的activity並將它們置入所在的任務中。「standard」和「singleTop」activity則能夠在堆棧的任意位置出現。

是否要載入新的類實例以處理新的intent。對默認的"standard"模式來講,對於每一個新intent都會建立一個新的實例以進行響應,每一個實例僅處理一個intent。「singleTop」模式下,若是activity位於目的任務堆棧的最上面,則重用目前現存的activity來處理新的intent。若是它不是在堆棧頂部,則不會發生重用。而是建立一個新實例來處理新的intent並將其推入堆棧。
舉例來講,假設一個任務的堆棧由根activityA和activity B、C和位於堆棧頂部的D組成,即堆棧A-B-C-D。一個針對D類型的activity的intent抵達的時候,若是D是默認的「standard」加載模式,則建立並加載一個新的類實例,因而堆棧變爲A-B-C-D-D。 然而,若是D的載入模式爲「singleTop」,則現有的實例會對新intent進行處理(由於它位於堆棧頂部)而堆棧保持A-B-C-D的形態。

換言之,若是新抵達的intent是針對B類型的activity,則不管B的模式是「standard」仍是「singleTop」 ,都會加載一個新的B的實例(由於B不位於堆棧的頂部),而堆棧的順序變爲A-B-C-D-B。

如前所述,「singleTask」或「singleInstance」模式的activity永遠不會存在多於一個實例。因此實例將處理全部新的intent。一個「singleInstance」模式的activity永遠保持在堆棧的頂部(由於它是那個堆棧中惟一的一個activity),因此它一直堅守在處理intent的崗位上。然而,對一個「singleTask」模式的activity來講,它上面可能有,也可能沒有別的activity和它處於同一堆棧。在有的狀況下,它就不在可以處理intent的位置上,則那個intent將被捨棄。(即使在intent被捨棄的狀況下,它的抵達仍將使這個任務切換至前臺,並一直保留)

當一個現存的activity被要求處理一個新的intent的時候,會調用onNewIntent()方法來將intent對象傳遞至activity。(啓動activity的原始intent對象能夠經過調用getIntent()方法得到。)

請注意,當一個新的activity實例被建立以處理新的intent的時候,用戶總能夠按下BACK鍵來回到前面的狀態(回到前一個activity)。但當使用現存的activity來處理新intent的時候,用戶是不能靠按下BACK鍵回到當這個新intent抵達以前的狀態的。

想得到更多關於加載模式的內容,請參閱 元素的描述。

清理堆棧
若是用戶離開一個任務很長一段時間,系統會清理該任務中除了根activity以外的全部activity。當用戶再次回到這個任務的時候,除了只剩下初始化activity尚存以外,其他都跟用戶上次離開它的時候同樣。這樣作的緣由是:在一段時間以後,用戶再次回到一個任務的時候,他們更指望放棄他們以前的所做所爲,作些新的事情。

這些屬於默認行爲,另外,也存在一些activity的屬性用以控制並改變這些行爲:

alwaysRetainTaskState 屬性

若是一個任務的根activity中此屬性設置爲「true」,則上述默認行爲不會發生。任務將在很長的一段時間內保留它堆棧內的全部activity。

clearTaskOnLaunch屬性

若是一個任務的根activity中此屬性設置爲「true」,則每當用戶離開這個任務和返回它的時候,堆棧都會被清空至只留下rootactivity。換句話說,這是alwaysRetainTaskState的另外一個極端。哪怕僅是過了一小會兒,用戶回到任務時,也是見到它的初始狀態。

finishOnTaskLaunch屬性

這個屬性與clearTaskOnLaunch屬性類似,但它僅做用於單個的activity,而不是整個的task。並且它可使任意activity都被清理,甚至根activity也不例外。當它設置爲「true」的時候,此activity僅作爲任務的一部分存在於當前回話中,一旦用戶離開並再次回到這個任務,此activity將不復存在。

此外,還有別的方式從堆棧中移除一個activity。若是一個intent對象包含FLAG_ACTIVITY_CLEAR_TOP標記,並且目標任務的堆棧中已經存在了一個可以響應此intent的activity類型的實例。則這個實例之上的全部activity都將被清理以使它位於堆棧的頂部來對intent作出響應。若是此時指定的activity的加載模式爲「standard」,則它自己也會從堆棧中移除,並加載一個新的實例來處理到來的intent。這是由於加載模式爲「standard」的activity總會建立一個新實例來處理新的intent。

FLAG_ACTIVITY_CLEAR_TOP與FLAG_ACTIVITY_NEW_TASK常常合併使用。這時,這些標記提供了一種定位其它任務中現存的activity並將它們置於能夠對intent作出響應的位置的方法。

啓動任務
當一個activity被指定一個「android.intent.action.MAIN」作爲動做,以及「android.intent.category.LAUNCHER」作爲類別的intent過濾器以後(在前述intent過濾器一節中已經有了這個示例),它就被設置爲一個任務的入口點。這樣的過濾器設置會在應用程序加載器中爲此activity顯示一個圖標和標籤,以供用戶加載任務或加載以後在任意時間回到這個任務。

第二個能力至關重要:用戶必須能夠離開一個任務,並在一段時間後返回它。出於這個考慮,加載模式被設定爲「singleTask」和「singleInstance」的activity老是會初始化一個新任務,這樣的activity僅能用於指定了一個MAIN和LAUNCHER過濾器的狀況之下。咱們來舉例說明若是沒指定過濾器的狀況下會發生的事情:一個intent加載了一個「singleTask」的activity,初始化了一個新任務,用戶在這個任務中花費了一些時間來完成工做。而後用戶按下了HOME鍵。因而任務被要求轉至後臺並被主屏幕所掩蓋。由於它並無在應用程序加載器中顯示圖標,這將致使用戶沒法再返回它。

相似的困境也可由FLAG_ACTIVITY_NEW_TASK標記引發。若是此標記使一個activity啓動了一個新任務繼而用戶按下了HOME鍵離開了它,則用戶必需要有一些方法再次回到這個任務。一些實體(諸如通知管理器)老是在另外的任務中啓動新activity,而不是作爲它們本身的一部分,因此它們老是將FLAG_ACTIVITY_NEW_TASK標記包含在intent裏面並傳遞給startActivity()。若是你寫了一個能被外部實體使用這個標記調用的activity,你必須注意要給用戶留一個返回這個被外部實體啓動的任務的方法。

當你不想讓用戶再次返回一個activity的狀況下,能夠將 元素的 finishOnTaskLaunch設置爲「true」。參見前述清理堆棧。.

進程和線程
當一個應用程序開始運行它的第一個組件時,Android會爲它啓動一個Linux進程,並在其中執行一個單一的線程。默認狀況下,應用程序全部的組件均在這個進程的這個線程中運行。

然而,你也能夠安排組件在其餘進程中運行,並且能夠爲任意進程衍生出其它線程。

進程
組件運行所在的進程由manifest文件所控制。組件元素—— ——都有一個 process 屬性來指定組件應當運行於哪一個進程以內。這些屬性能夠設置爲使每一個組件運行於它本身的進程以內,或一些組件共享一個進程而其他的組件不這麼作。它們也能夠設置爲令不一樣應用程序的組件在一個進程中運行——使應用程序的組成部分共享同一個Linux用戶ID並賦以一樣的權限。 元素也有一個process屬性,以設定全部組件的默認值。

全部的組件實例都位於特定進程的主線程內,而對這些組件的系統調用也將由那個線程進行分發。通常不會爲每一個實例建立線程。所以,某些方法老是運行在進程的主線程內,這些方法包括諸如View.onKeyDown()這樣報告用戶動做以及後面 組件生命週期一節所要討論的生命週期通告的。這意味着組件在被系統調用的時候,不該該施行長時間的抑或阻塞的操做(諸如網絡相關操做或是循環計算),由於這將阻塞一樣位於這個進程的其它組件的運行。你應該如同下面線程一節所敘述的那樣,爲這些長時間操做衍生出一個單獨的線程進行處理。

在可用內存不足而又有一個正在爲用戶進行服務的進程須要更多內存的時候,Android有時候可能會關閉一個進程。而在這個進程中運行着的應用程序也所以被銷燬。當再次出現須要它們進行處理的工做的時候,會爲這些組件從新建立進程。

在決定結束哪一個進程的時候,Android會衡量它們對於用戶的相對重要性。好比說,相對於一個仍有用戶可見的activity的進程,它更有可能去關閉一個其activity已經不爲用戶所見的進程。也能夠說,決定是否關閉一個進程主要依據在那個進程中運行的組件的狀態。這些狀態將在後續的一節組件生命週期中予以說明。

線程
儘管你能夠把你的應用程序限制於一個單獨的進程中,有時,你仍然須要衍生出一個線程以處理後臺任務。由於用戶界面必須很是及時的對用戶操做作出響應,因此,控管activity的線程不該用於處理一些諸如網絡下載之類的耗時操做。全部不能在瞬間完成的任務都應安排到不一樣的線程中去。

線程在代碼中是以標準Java Thread對象建立的。Android提供了不少便於管理線程的類: Looper用於在一個線程中運行一個消息循環, Handler用於處理消息,HandlerThread 用於使用一個消息循環啓用一個線程。

遠程過程調用
Android有一個輕量級的遠程過程調用(RPC)機制:即在本地調用一個方法,但在遠程(其它的進程中)進行處理,而後將結果返回調用者。這將方法調用及其附屬的數據以系統能夠理解的方式進行分離,並將其從本地進程和本地地址空間傳送至遠程過程和遠程地址空間,並在那裏從新裝配並對調用作出反應。返回的結果將以相反的方向進行傳遞。Android提供了完成這些工做所需的全部的代碼,以使你能夠集中精力來實現RPC接口自己。

RPC接口能夠只包括方法。即使沒有返回值,全部方法仍以同步的方式執行(本地方法阻塞直至遠程方法結束)。

簡單的說,這套機制是這樣工做的:一開始,你用簡單的IDL(界面描繪語言)聲明一個你想要實現的RPC接口。而後用 aidl 工具爲這個聲明生成一個Java接口定義,這個定義必須對本地和遠程進程均可見。它包含兩個內部類,以下圖所示:

 

內部類中有管理實現了你用IDL聲明的接口的遠程方法調用所須要的全部代碼。兩個內部類均實現了 IBinder接口。一個用於系統在本地內部使用,你些的代碼能夠忽略它;另一個,咱們稱爲Stub,擴展了Binder類。除了實現了IPC調用的內部代碼以外,它還包括了你聲明的RPC接口中的方法的聲明。你應該如上圖所示的那樣寫一個Stub的子類來實現這些方法。

通常狀況下,遠程過程是被一個服務所管理的(由於服務能夠通知系統關於進程以及它鏈接到別的進程的信息)。它包含着 aidl工具產生的接口文件和實現了RPC方法的Stub的子類。而客戶端只須要包括aidl工具產生的接口文件。

下面將說明服務與其客戶端之間的鏈接是如何創建的:

服務的客戶端(位於本地)應該實現 onServiceConnected() 和 onServiceDisconnected() 方法。這樣,當至遠程服務的鏈接成功創建或者斷開的時候,它們會收到通知。這樣它們就能夠調用 bindService() 來設置鏈接。
而服務則應該實現 onBind() 方法以接受或拒絕鏈接。這取決於它收到的intent(intent將傳遞給bindService())。若是接受了鏈接,它會返回一個Stub的子類的實例。
若是服務接受了鏈接,Android將會調用客戶端的onServiceConnected() 方法,並傳遞給它一個IBinder對象,它是由服務所管理的Stub的子類的代理。經過這個代理,客戶端能夠對遠程服務進行調用。
線程安全方法
在一些狀況下,你所實現的方法有可能會被多於一個的線程所調用,因此它們必須被寫成線程安全的。

對於咱們上一節所討論的RPC機制中的能夠被遠程調用的方法來講,這是必須首先考慮的。若是針對一個IBinder對象中實現的方法的調用源自這個IBinder對象所在的進程時,這個方法將會在調用者的線程中執行。然而,若是這個調用源自其它的進程,則這個方法將會在一個線程池中選出的線程中運行,這個線程池由Android加以管理,並與IBinder存在於同一進程內;這個方法不會在進程的主線程內執行。反過來講,一個服務的 onBind() 方法應爲服務進程的主線程所調用,而實現了由 onBind() 返回的對象(好比說,一個實現了RPC方法的Stub的子類)的方法將爲池中的線程所調用。由於服務能夠擁有多於一個的客戶端,而同一時間,也會有多個池中的線程調用同一個IBinder方法。所以IBinder方法必須實現爲線程安全的。

相似的,一個內容提供者能接受源自其它進程的請求數據。儘管ContentResolver和ContentProvider類隱藏了交互溝經過程的管理細節,ContentProvider會由query(), insert(), delete(), update()和getType()方法來相應這些請求,而這些方法也都是由那個內容提供者的進程中所包涵的線程池提供的,而不是進程的主線程自己。因此這些有可能在同一時間被不少線程調用的方法也必須被實現爲線程安全的。

組件生命週期
應用程序組件有其生命週期──由Android初始化它們以相應intent直到這個實例被摧毀。在此之間,它們有時是激活的有時則相反。或者,若是它是一個activity,則是可爲用戶所見或者不能。這一節討論了activity、服務以及廣播接收器的生命週期,包括它們在生命週期中的狀態、在狀態之間轉變時通知你的方法、以及當這些進程被關閉或實例被摧毀時,這些狀態產生的效果。

Activity生命週期
一個activity主要有三個狀態:

當在屏幕前臺時(位於當前任務堆棧的頂部),它是活躍或運行的狀態。它就是相應用戶操做的activity。
當它失去焦點但仍然對用戶可見時,它處於暫停狀態。便是:在它之上有另一個activity。這個activity也許是透明的,或者未能徹底遮蔽全屏,因此被暫停的activity仍對用戶可見。暫停的activity仍然是存活狀態(它保留着全部的狀態和成員信息並鏈接至窗口管理器),但當系統處於極低內存的狀況下,仍然能夠殺死這個activity。

若是它徹底被另外一個activity覆蓋是,它處於中止狀態。它仍然保留全部的狀態和成員信息。然而它不在爲用戶可見,因此它的窗口將被隱藏,若是其它地方須要內存,則系統常常會殺死這個activity。

若是一個activity處於暫停或中止狀態,系統能夠經過要求它結束(調用它的 finish() 方法)或直接殺死它的進程來將它驅出內存。當它再次爲用戶可見的時候,它只能徹底從新啓動並恢復至之前的狀態。

當一個activity從這個狀態轉變到另外一個狀態時,它被如下列protected方法所通知:

void onCreate(Bundle savedInstanceState)
void onStart()
void onRestart()
void onResume()
void onPause()
void onStop()
void onDestroy()

你能夠重載全部這些方法以在狀態改變時進行合適的工做。全部的activity都必須實現 onCreate() 用以當對象第一次實例化時進行初始化設置。不少activity會實現 onPause()以提交數據變化或準備中止與用戶的交互。

調用父類
全部activity生命週期方法的實現都必須先調用其父類的版本。好比說:

protected void onPause() {    super.onPause();    . . .}總得來講,這七個方法定義了一個activity完整的生命週期。實現這些方法能夠幫助你監察三個嵌套的生命週期循環:

一個activity 完整的生命週期 自第一次調用 onCreate()開始,直至調用onDestroy()爲止。activity在onCreate()中設置全部「全局」狀態以完成初始化,而在onDestroy()中釋放全部系統資源。好比說,若是activity有一個線程在後臺運行以從網絡上下載數據,它會以 onCreate()建立那個線程,而以 onDestroy()銷燬那個線程。
一個activity的 可視生命週期自 onStart() 調用開始直到相應的 onStop()調用。在此期間,用戶能夠在屏幕上看到此activity,儘管它也許並非位於前臺或者正在與用戶作交互。在這兩個方法中,你能夠管控用來向用戶顯示這個activity的資源。好比說,你能夠在onStart() 中註冊一個BroadcastReceiver 來監控會影響到你UI的改變,而在onStop() 中來取消註冊,這時用戶是沒法看到你的程序顯示的內容的。onStart() 和 onStop() 方法能夠隨着應用程序是否爲用戶可見而被屢次調用。

一個activity的 前臺生命週期 自 onResume() 調用起,至相應的 onPause()調用爲止。在此期間,activity位於前臺最上面並與用戶進行交互。activity會常常在暫停和恢復之間進行狀態轉換──好比說當設備轉入休眠狀態或有新的activity啓動時,將調用onPause() 方法。當activity得到結果或者接收到新的intent的時候會調用onResume() 方法。所以,在這兩個方法中的代碼應當是輕量級的。

下圖展現了上述循環過程以及activity在這個過程之中歷經的狀態改變。着色的橢圓是activity能夠經歷的主要狀態。矩形框表明了當activity在狀態間發生改變的時候,你進行操做所要實現的回調方法。

 

下表詳細描述了這些方法,並在activity的整個生命週期中定位了它們。

方法 描述 可被殺死 下一個
onCreate() 在activity第一次被建立的時候調用。這裏是你作全部初始化設置的地方──建立視圖、綁定數據至列表等。若是曾經有狀態記錄(參閱後述Saving Activity State。),則調用此方法時會傳入一個包含着此activity之前狀態的包對象作爲參數。
總繼之以onStart()。
 否 onStart()
     onRestart() 在activity中止後,在再次啓動以前被調用。
總繼之以onStart()。
 否 onStart()
onStart() 當activity正要變得爲用戶所見時被調用。
當activity轉向前臺時繼以onResume(),在activity變爲隱藏時繼以onStop()。
 否 onResume()
or
onStop()
     onResume() 在activity開始與用戶進行交互以前被調用。此時activity位於堆棧頂部,並接受用戶輸入。
繼之以onPause()。
 否 onPause()
onPause() 當系統將要啓動另外一個activity時調用。此方法主要用來將未保存的變化進行持久化,中止相似動畫這樣耗費CPU的動做等。這一切動做應該在短期內完成,由於下一個activity必須等到此方法返回後纔會繼續。
當activity從新回到前臺是繼以onResume()。當activity變爲用戶不可見時繼以onStop()。
 是 onResume()
or
onStop()
onStop() 當activity再也不爲用戶可見時調用此方法。這可能發生在它被銷燬或者另外一個activity(多是現存的或者是新的)回到運行狀態並覆蓋了它。
若是activity再次回到前臺跟用戶交互則繼以onRestart(),若是關閉activity則繼以onDestroy()。
 是 onRestart()
or
onDestroy()
onDestroy() 在activity銷燬前調用。這是activity接收的最後一個調用。這可能發生在activity結束(調用了它的 finish() 方法)或者由於系統須要空間因此臨時的銷燬了此acitivity的實例時。你能夠用isFinishing() 方法來區分這兩種狀況。 是 nothing

請注意上表中可被殺死一列。它標示了在方法返回後,還沒執行activity的其他代碼的任意時間裏,系統是否能夠殺死包含此activity的進程。三個方法(onPause()、 onStop()和onDestroy())被標記爲「是」。onPause()是三個中的第一個,它也是惟一一個在進程被殺死以前必然會調用的方法──onStop() 和 onDestroy() 有可能不被執行。所以你應該用 onPause() 來將全部持久性數據(好比用戶的編輯結果)寫入存儲之中。

在可被殺死一列中標記爲「否」的方法在它們被調用時將保護activity所在的進程不會被殺死。因此只有在onPause()方法返回後到onResume() 方法被調用時,一個activity才處於可被殺死的狀態。在onPause()再次被調用並返回以前,它不會被系統殺死。

如後面一節進程和生命週期所述,即便是在這裏技術上沒有被定義爲「可殺死」的activity仍然有可能被系統殺死──但這僅會發生在實在沒有其它方法的極端狀況之下。

保存activity狀態
當系統而不是用戶本身出於回收內存的考慮,關閉了一個activity以後。用戶會指望當他再次回到那個activity的時候,它仍保持着上次離開時的樣子。

爲了獲取activity被殺死前的狀態,你應該爲activity實現onSaveInstanceState() 方法。Android在activity有可能被銷燬以前(即onPause() 調用以前)會調用此方法。它會將一個以名稱-值對方式記錄了activity動態狀態的Bundle 對象傳遞給該方法。當activity再次啓動時,這個Bundle會傳遞給onCreate()方法和隨着onStart()方法調用的onRestoreInstanceState(),因此它們兩個均可以恢復捕獲的狀態。

與onPause()或先前討論的其它方法不一樣,onSaveInstanceState() 和 onRestoreInstanceState() 並非生命週期方法。它們並非總會被調用。好比說,Android會在activity易於被系統銷燬以前調用 onSaveInstanceState(),但用戶動做(好比按下了BACK鍵)形成的銷燬則不調用。在這種狀況下,用戶沒打算再次回到這個activity,因此沒有保存狀態的必要。

由於onSaveInstanceState()不是總被調用,因此你應該只用它來爲activity保存一些臨時的狀態,而不能用來保存持久性數據。而是應該用onPause()來達到這個目的。

協調activity
當一個activity啓動了另一個的時候,它們都會經歷生命週期變化。一個會暫停乃至中止,而另外一個則啓動。這種狀況下,你可能須要協調好這些activity:

生命週期回調順序是已經定義好的,尤爲是在兩個activity在同一個進程內的狀況下:

調用當前activity的 onPause() 方法。
接着,順序調用新啓動activity的onCreate()、 onStart()和onResume()方法。
而後,若是啓動的activity再也不於屏幕上可見,則調用它的onStop()方法。
服務生命週期
服務以兩種方式使用:

它能夠啓動並運行,直至有人中止了它或它本身中止。在這種方式下,它以調用Context.startService()啓動,而以調用Context.stopService()結束。它能夠調用Service.stopSelf() 或 Service.stopSelfResult()來本身中止。不論調用了多少次startService()方法,你只須要調用一次stopService()來中止服務。
它能夠經過本身定義並暴露出來的接口進行程序操做。客戶端創建一個到服務對象的鏈接,並經過那個鏈接來調用服務。鏈接以調用Context.bindService()方法創建,以調用 Context.unbindService()關閉。多個客戶端能夠綁定至同一個服務。若是服務此時尚未加載,bindService()會先加載它。
這兩種模式並非徹底分離的。你能夠綁定至一個用 startService()啓動的服務。好比說,一個後臺音樂播放服務能夠調用startService()並傳遞給它一個包含欲播放的音樂列表的Intent對象來啓動。不久,當用戶想要對播放器進行控制或者查看當前播放曲目的詳情時,會啓用一個activity,調用bindService()鏈接到服務來完成操做。在這種狀況下,直到綁定鏈接關閉stopService() 纔會真正中止一個服務。

與activity同樣,服務也有一系列你能夠實現以用於監控其狀態變化的生命週期方法。但相對於activity要少一些,只有三個,並且,它們是public屬性,並不是protected:

void onCreate()
void onStart(Intent intent)
void onDestroy()

倚仗實現這些方法,你監控服務的兩個嵌套的生命週期循環:

服務的完整生命週期始於調用onCreate()而終於onDestroy()方法返回。如同activity同樣,服務在onCreate()裏面進行它本身的初始化,而在onDestroy()裏面釋放全部資源。好比說,一個音樂回放服務能夠在onCreate()中建立播放音樂的線程, 而在onDestroy()中中止這個線程。
服務的活躍生命週期始於調用onStart()。這個方法用於處理傳遞給startService()的Intent對象。音樂服務會打開Intent來探明將要播放哪首音樂,並開始播放。

服務中止時沒有相應的回調方法──不存在onStop()方法。

onCreate()和onDestroy()方法在全部服務中都會被調用,不論它們是由Context.startService()仍是由Context.bindService()所啓動的。而onStart()僅會被startService()所啓用的服務調用。

若是一個服務容許別的進程綁定,則它還會有如下額外的回調方法以供實現:

IBinder onBind(Intent intent)
boolean onUnbind(Intent intent)
void onRebind(Intent intent)

傳遞給bindService的Intent的對象也會傳遞給onBind()回調方法,而傳遞給unbindService()的Intent對象一樣傳遞給onUnbind()。若是服務容許綁定,onBind()將返回一個供客戶端與服務進行交互的通信渠道。若是有新的客戶端鏈接至服務,則onUnbind()方法能夠要求調用onRebind() 。

下圖描繪了服務的回調方法。儘管圖中對由startService 和startService方法啓動的服務作了區分,但要記住,不論一個服務是怎麼啓動的,它均可能容許客戶端的鏈接,因此任何服務均可以接受onBind()和onUnbind()調用。

 

廣播接收器生命週期
廣播接收器只有一個回調方法:

void onReceive(Context curContext, Intent broadcastMsg)

當廣播消息抵達接收器時,Android調用它的onReceive() 方法並將包含消息的Intent對象傳遞給它。廣播接收器僅在它執行這個方法時處於活躍狀態。當onReceive()返回後,它即爲失活狀態。

擁有一個活躍狀態的廣播接收器的進程被保護起來而不會被殺死。但僅擁有失活狀態組件的進程則會在其它進程須要它所佔有的內存的時候隨時被殺掉。

這種方式引出了一個問題:若是響應一個廣播信息須要很長的一段時間,咱們通常會將其歸入一個衍生的線程中去完成,而不是在主線程內完成它,從而保證用戶交互過程的流暢。若是onReceive()衍生了一個線程而且返回,則包涵新線程在內的整個進程都被會判爲失活狀態(除非進程內的其它應用程序組件仍處於活躍狀態),因而它就有可能被殺掉。這個問題的解決方法是令onReceive()啓動一個新服務,並用其完成任務,因而系統就會知道進程中仍然在處理着工做。

下一節中,咱們會討論更多進程易誤殺的問題。

進程與生命週期
Android系統會盡量長的延續一個應用程序進程,但在內存太低的時候,仍然會不可避免須要移除舊的進程。爲決定保留或移除一個進程,Android將每一個進程都放入一個「重要性層次」中,依據則是它其中運行着的組件及其狀態。重要性最低的進程首先被消滅,而後是較低的,依此類推。重要性共分五層,依據重要性列表以下:

前臺進程是用戶操做所必須的。當知足以下任一條件時,進程被認爲是處於前臺的:
它運行着正在與用戶交互的activity(Activity對象的 onResume() 方法已被調用)。
一個正在與用戶交互的activity使用着它提供的一個服務。

它包含着一個正在執行生命週期回調方法(onCreate()、onStart()或onDestroy())的Service對象。

它包含着一個正在執行 onReceive() 方法的BroadcastReceiver對象。

任一時間下,僅有少數進程會處於前臺,僅當內存實在沒法供給它們維持同時運行時纔會被殺死。通常來講,在這種狀況下,設備已然處於使用虛擬內存的狀態,必需要殺死一些前臺進程以用戶界面保持響應。

可視進程沒有前臺組件,但仍可被用戶在屏幕上所見。當知足以下任一條件時,進程被認爲是可視的:、

它包含着一個不在前臺,但仍然爲用戶可見的activity(它的onPause()方法被調用)。這種狀況可能出如今如下狀況:好比說,前臺activity是一個對話框,而以前的activity位於其下並能夠看到。
它包含了一個綁定至一個可視的activity的服務。

可視進程依然被視爲是很重要的,非到不殺死它們便沒法維持前臺進程運行時,纔會被殺死。

服務進程是由 startService() 方法啓動的服務,它不會變成上述兩類。儘管服務進程不會直接爲用戶所見,但它們通常都在作着用戶所關心的事情(好比在後臺播放mp3或者從網上下載東西)。因此係統會盡可能維持它們的運行,除非系統內存不足以維持前臺進程和可視進程的運行須要。

背景進程包含目前不爲用戶所見的activity(Activity對象的 onStop() 方法已被調用)。這些進程與用戶體驗沒有直接的聯繫,能夠在任意時間被殺死以回收內存供前臺進程、可視進程以及服務進程使用。通常來講,會有不少背景進程運行,因此它們通常存放於一個LRU(最後使用)列表中以確保最後被用戶使用的activity最後被殺死。若是一個activity正確的實現了生命週期方法,並捕獲了正確的狀態,則殺死它的進程對用戶體驗不會有任何不良影響。

空進程不包含任何活動應用程序組件。這種進程存在的惟一緣由是作爲緩存以改善組件再次於其中運行時的啓動時間。系統常常會殺死這種進程以保持進程緩存和系統內核緩存之間的平衡。

Android會依據進程中當前活躍組件的重要程度來儘量高的估量一個進程的級別。好比說,若是一個進程中同時有一個服務和一個可視的activity,則進程會被斷定爲可視進程,而不是服務進程。

此外,一個進程的級別可能會因爲其它進程依賴於它而升高。一個爲其它進程提供服務的進程級別永遠高於使用它服務的進程。好比說,若是A進程中的內容提供者爲進程B中的客戶端提供服務,或進程A中的服務爲進程B中的組件所綁定,則A進程最低也會被視爲與進程B擁有一樣的重要性。

由於運行着一個服務的進程重要級別總高於一個背景activity。因此一個activity以啓動一個服務的方式啓動一個長時間運行過程比簡單的衍生一個線程來進行處理要好。尤爲是當處理過程比activity自己存在時間要長的狀況之下。咱們以背景音樂播放和上傳一個相機拍攝的圖片至網站上爲例。使用服務則不論activity發生何事,都至少能夠保證操做擁有「服務進程」的權限。如上一節廣播接收器生命週期 所提到的,這也正是廣播接收器使用服務,而不是使用線程來處理耗時任務的緣由。

 

本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/iefreer/archive/2009/08/17/4457015.aspx

相關文章
相關標籤/搜索