Android應用程序是用Java語言編寫的。編譯過後的字節碼,以及應用程序要求的其他數據和資源文件,通過aapt工具被綁定在一起,稱為Android包,這是一個帶.apk後綴的檔案文件。這個文件也是用戶下載到他們設備上的文件。所有的代碼在一個單一的.apk文件中,組成一個“應用程序”。
從許多方面來說,每個Android應用程序存活在它們自己的世界中:
q 默認地,每一個應用程序運行在它自己的Linux進程中。當應用程序的任何代碼需要被執行時,Android啟動進程;當不再需要時,或者系統資源被其他應用程序所要求時,關閉進程。
q 每一個進程有它自己的Java虛擬機(JVM),因此應用程序代碼獨立與所有其他應用程序代碼而運行。
q 默認地,每一個應用程序被分配一個唯一的Linux用戶ID。通過設置權限許可,應用程序的文件只對該用戶可見,只對應用程序本身可見—雖然有辦法將其導出到其他應用程序。
有可能安排兩個應用程序共享同一用戶ID,在這種情況下,它們可以彼此看見對方的文件。要保全系統資源,具有相同ID的應用程序也可以被組織起來運行在同一Linux進程中,共享同一VM。
Android一 個最核心的特性是,一個應用程序可以利用其它應用程序的元素(假設這些程序允許這樣做)。例如,如果你的應用程序需要顯示一個滾動的圖像列表,而其它應用 程序已經開發了一個合適的圖像滾動器並且允許其被其他人使用,那麼你可以要求使用該圖像滾動器來完成這項工作,而不必自己再開發一個。你的應用程序不必合 並或鏈接到其他應用程序的代碼。相反,當需要發生時,它僅是簡單地啟動其他應用程序。
要能如此地工作,系統必須在需要應用程序任何部分時,能啟動該應用程序進程,並為該部分實例化Java對象。因此,不像在其他大多數系統上的應用程序,Android應用程序沒有一個為應用程序的任何事設置單一的入口點(例如,沒有main()函數)。相反,他們擁有一些主要組件,系統可以實例化這些組件並且根據需要來運行。總共有四類組件:
q Activities
q Services
q Broadcast receivers
q Content providers
Activities
一個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”中會專門講述)