Android應用程序是用Java語言編寫的。編譯事後的字節碼,以及應用程序要求的其餘數據和資源文件,經過aapt工具被綁定在一塊兒,稱爲 Android包,這是一個帶.apk後綴的檔案文件。這個文件也是用戶下載到他們設備上的文件。全部的代碼在一個單一的.apk文件中,組成一個「應用程序」。android
從許多方面來講,每一個Android應用程序存活在它們本身的世界中:數據庫
有可能安排兩個應用程序共享同一用戶ID,在這種狀況下,它們能夠彼此看見對方的文件。要保全系統資源,具備相同ID的應用程序也能夠被組織起來運行在同一Linux進程中,共享同一VM。網絡
Android一 個最核心的特性是,一個應用程序能夠利用其它應用程序的元素(假設這些程序容許這樣作)。例如,若是你的應用程序須要顯示一個滾動的圖像列表,而其它應用 程序已經開發了一個合適的圖像滾動器而且容許其被其餘人使用,那麼你能夠要求使用該圖像滾動器來完成這項工做,而沒必要本身再開發一個。你的應用程序沒必要合 並或連接到其餘應用程序的代碼。相反,當須要發生時,它僅是簡單地啓動其餘應用程序。app
要能如此地工做,系統必須在須要應用程序任何部分時,能啓動該應用程序進程,併爲該部分實例化Java對象。所以,不像在其餘大多數系統上的應用程序,Android應用程序沒有一個爲應用程序的任何事設置單一的入口點(例如,沒有main()函數)。相反,他們擁有一些主要組件,系統能夠實例化這些組件而且根據須要來運行。總共有四類組件:異步
q Activitieside
q Services函數
q Broadcast receivers工具
q Content providers佈局
Activitiesspa
一個activity表明一個可視的用戶接口,該接口致力於用戶能作一些操做。例如,一個activity可能表明一個菜單項列表,用戶能夠從中選擇,或者它可能顯示帶有標題說明的圖像。一個文本消息應用程序可能有一個activity來顯示一個聯繫人列表以發送消息,有第二個activity來寫消息到被選擇的聯繫人,以及其它activity來從新獲取舊的消息或改變設置。雖然它們一塊兒工做來造成一個內聚性的用戶接口,但實際上每個 activity是獨立與其餘的activity的。每個activity做爲Activity基類的一個子類來實現的。
一個應用程序可能僅由一個activity組成,也可能象剛纔提到的文本消息應用程序一個,由數個activity組成。Activity是什麼,以及有多少activity,固然依賴於應用程序及其設計。典型地,其中一個activity被標記爲第一個,當應用程序被啓動時,它應該被首先呈現出來。從一個activity遷移到另外一個activity是經過當前activity啓動下一個activity來完成的。
每個activity都有一個默認的繪製窗口。一般,該窗口填滿屏幕,可是它也可能比屏幕小而且浮動在其它窗口上面。一個activity還能利用另外的窗口—例如,一個位於activity中間的彈出對話框用於對用戶作出響應,或者一個當用戶選擇一個屏幕上特定條目時帶給用戶重要信息的窗口。
窗口的可視內容由一個具備層次的視圖所提供—從基類View繼承來的對象。每個視圖控制一個窗口中特定的矩形空間。父視圖容納並組織其子視圖的佈局。葉子視圖(在層次的最末端)在它們所控制的矩形中繪製並對做用於這一區域的用戶動做作出響應。所以,視圖是activity與用戶的交互發生的地方。例如,一個視圖可能會顯示一個小圖像,而且當用戶輕擊該圖像時發起一個動做。Android有許多現成的視圖可使用,包括按鈕、文本域、滾動條、菜單項、複選框,等等。
一個視圖層次是由Activity.setContentView()方法佈局到一個activity中的。內容視圖(content view)是位於層次根部的View對象。
Services
一個service沒有可視化的用戶接口,而是運行在後臺一個無限期限內。例如,當用戶試圖作其餘事情時,一個service在後臺播放音樂,或者它也可能在網絡上提取數據,或作些計算並提供結果給須要它的activity。每個service繼承自Service基類。
一個最好的例證是一個媒體播放器從一個播放列表中播放歌曲。播放器應用程序可能有一到多個activity以容許用戶來選擇歌曲並開始播放。然而,音樂播放自己不能被一個activity處理,由於用戶會指望音樂持續播放,甚至是在他們離開播放器並開始作其餘事情時。要保持音樂繼續播放,媒體播放器 activity能夠開始一個service來在後臺運行。而後系統將保持音樂播放服務持續運行,甚至在啓動播放器的activity離開屏幕之後也會持續播放。
鏈接(綁定)到一個正在進行的service(若是service尚未運行,就啓動它)也是可能的。當鏈接後,你能夠經過service暴露的接口與service進行通訊。對於音樂service,這個接口可能容許用戶暫停、後退、中止以及恢復播放。
像activity和其它組件同樣,service運行在應用程序進程的主線程中。所以它們不會阻塞其它組件或用戶接口,他們常常爲耗時的任務(如音樂播放)產生另外的線程。
Broadcast receivers
一個broadcast receiver是一個什麼也不作的組件,除了它接受廣播公告並對其作出反應。許多廣播源(broadcast orginate)在系統代碼中----例如,聲明時區的改變,電量太低,一個圖像已經被拍照,或者用戶改變了一個語言參數。應用程序還能夠啓動一個廣播 ----例如,讓其餘應用程序知道一些數據已經被下載到設備上而且可使用它們了。
一個應用程序能夠有許多廣播接收器(broadcast receivers)來對任何它認爲重要的公告作出響應。全部的接收器擴展自BroadcastReceiver基類。
廣播接收器並不顯示一個用戶接口。然而,在對它們接收到的信息作出響應時,它們能夠啓動一個activity,或者它們可使用通知管理器(NotificationManager)來提醒用戶。通知能夠經過多種方式來得到用戶的注意----閃爍背景照明燈,振動設備,播放聲音等等。它們典型地會放置一個固定的圖標在狀態欄,用戶能夠打開這個圖標來查看信息。
Content providers
一個Content provider使得一系列特定的應用程序數據對其餘應用程序可用。這些數據能夠存放在文件系統中,在一個SQLite數據庫中,或者在任何其它能夠被感知的形式中。內容提供器(content provider)擴展自ContentProvider基類,實現了一系列標準的方法,這些方法可以使其餘應用程序來從新獲取並存儲它所控制的類型的數據。然而,應用程序並不直接調用這些方法。相反,它們使用一個ContentResolver對象並調用其方法。一個ContentResolver能夠與任何內容提供器通話,它與提供者合做來管理任何相關的通訊工序。(Content provider在稍後一節會專門講述)
不管什麼時候,只要有一個被特定的一個組件所處理的請求,Android就確保組件的應用程序處理正在運行,若是有必要就啓動它,而且保證組件的一個合適的實例是可用的,若是有必要就建立這個實例。
當一個請求來自一個ContentResolver時,內容提供器被激活。其餘三個組件----activities,services和 broadcast receivers----被名爲intents的異步消息所激活。一個intent是一個Intent對象,持有消息的內容。對於activities 和services來講,它意味着位於其餘事物中被請求的動做和指定要操做的數據的URI。例如,它可能會爲一個activity傳送一個請求以表明給用戶的一個圖片,或者讓用戶編輯一些文本。對於broadcast receivers,Intent對象意味着被公告/通知的動做。例如,它可能會通告有興趣的相關方,相機的按鈕被按下了。
有各自的方法來用於激活每一類組件:
q 經過傳遞一個Intent對象到Context.startActivity()或 Activity.startActivityForResult(),來啓動一個activity(或者讓作一些新的東西)。進行響應的 activity能夠經過調用其getIntent()方法來查看引發它被啓動的原始內容(intent)。Android調用該activity的 onNewIntent()方法來向其傳遞任何後續的intent。
一個activity常常啓動下一個activity。若是它指望從它所啓動的activity得到一個返回的結果,那麼它就要調用 startActivityForResult()而不是startActivity()。例如,若是它啓動一個讓用戶挑選照片的activity,那麼它可能指望返回被選中的照片。結果在一個Intent對象中被返回,而該Intent對象被傳遞給進行調用的activity的 onActivityResult()方法中。
q 經過傳遞一個Intent對象給Context.startService(),一個service被啓動(或者一個新的指令傳達給正在運行的 service)。Android調用該service的onStart()方法並將Intent對象傳遞給它。類似地,將一個intent傳遞給 Context.bindService(),可以在進行調用的組件和目標service之間創建一個持續的鏈接。該service在一個 onBind()調用中接收該Intent對象。(若是該service尚未運行,bindService()能有選擇地啓動它。)例如,一個 activity可能會與音樂播放服務創建一個鏈接,這樣它就能向用戶提供控制播放的方式(一個用戶接口)。該activity將調用 bindService()來創建這個鏈接,而後調用service所定義的方法來影響播放。(在稍後「遠程過程調用RPC」一節會專門講述 service)
q 應用程序能經過傳遞一個Intent對象到諸如 Context.sendBroadcast(),Context.sendOrderedBroadcast(),和 Context.sendStickyBroadcast()這些方法中來建立一個廣播。Android經過調用它們的onReceive()方法發佈該 Intent到全部感興趣的broadcast receivers。(更多有關Intent的信息,在稍後一節「Intents and Intent Filters」中會專門講述)
一個內容提供器只有當它在響應來自一個ContentResolver的請求時是活動的。一個廣播接收器只有當它在響應一個廣播消息時是活動的。所以沒有必要顯式地關閉這些組件。
另外一方面,activities提供用戶接口。它們與用戶處於一個長時間運行的會話中,而且可能保存有active,甚至在空閒時,只要會話在繼續。類似地,services也可能持續運行很長時間。所以Android有方法以一種有序的方式來關閉activities和services。
q 經過調用其finish()方法來關閉一個activity。一個activity能夠經過調用finishActivity()來關閉另外一個activity(它使用startActivityForResult()方法啓動的activity)。
q 經過調用其stopSelf()方法來中止一個service,或者經過調用Context.stopService()。
當組件再也不被使用時,或者當Android必須爲更多活動的組件而收回內存時,它們有可能被系統所關閉。在後面「組件的生命週期」一節中,將討論這種可能性及更多地細節。
在Android能啓動一個應用程序組件以前,它必須知道組件的存在。所以,應用程序在一個manifest文件中聲明它們的組件。manifest文件被綁定在一個Android包中。Android包是一個.apk文件,它還持有應用程序的代碼、文件和資源。
manifest是結構化的XML文件,而且對全部的應用程序來講,它老是被命名爲AndroidManifest.xml。除了聲明應用程序的組件以外,它還作不少事情,如命名應用程序須要連接到的庫(除了默認的Android庫以外),以及應用程序所指望被受權的任何權限驗證。
可是manifest的首要任務是告知Android關於應用程序的組件。例如,一個activity可能被聲明以下的內容:
<?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>
在這個manifest文件中,元素<activity>的name屬性命名實現了activity的Activity類的子類。而icon和label屬性則指向包含有一個圖標和標籤的資源文件,這些圖標和標籤能夠被顯示給用戶以表明這個activity。
另外一個組件以類似的方式被聲明--<service>元素聲明services,<receiver>元素聲明 broadcast receivers,以及<provider>元素聲明內容提供器(content providers)。不在manifest文件中聲明的activities,services和content providers對系統是不可見的,相應地永遠不會運行。然而,broadcast receivers既能夠在manifest文件中聲明,也能夠在代碼中(如BroadcastReceiver對象)動態地建立並經過調用 Context.registerReceiver()向系統註冊。(更多詳細內容,請參見後面的」AndroidManifest.xml文件」一節)
一個Intent對象能顯式地命名一個目標組件。若是這樣的話,Android會查找那個組件(基於在manifest文件中的聲明)並激活它。可是若是一個目標組件沒有被顯式地命名,Android必須定位最合適的組件來響應該Intent。它經過對Intent對象和潛在目標的intent filters的比較來完成這種定位。一個組件的intent過濾器告知Android該組件可以處理的intent種類。象其餘組件的基本信息同樣,它們是在manifest文件中聲明的。下面是前面示例代碼的一個擴展,爲activity添加了兩個intent過濾器。
<?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:mimeType="image/jpeg" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> . . . </application> </manifest>
上面示例代碼中的第一個過濾器—action「android.intent.action.MAIN」和 category「android.intent.category.LAUNCHER」—是一個通用的過濾器。它使得activity成爲在應用程序啓動器中顯示出來的應用程序之一。應用程序啓動器指的是顯示(列出)用戶能夠在設備上啓動的應用程序的屏幕。換句話說,這個activity是應用程序的入口,是用戶在啓動器中選擇應用程序時看得見的最初的一個。
第二個過濾器聲明一個該activity能夠在一個特定類型的數據上執行的動做。
一個組件能夠擁有任何數量的intent過濾器,每個都聲明一套不一樣的功能。若是沒有任何過濾器,那麼它只能被組件做爲目標顯式命名的intents所激活。
對於在代碼中建立和註冊的一個broadcst receiver,intent過濾器是直接做爲一個IntentFilter對象建立的。全部其餘過濾器都是在manifest中創建的。