Android開發(fā)入門:應(yīng)用程序基礎(chǔ)及組件
1、應(yīng)用程序基礎(chǔ)
Android 應(yīng)用程序是用Java編程語言寫的。編譯后的Java代碼——包括應(yīng)用程序要求的任何數(shù)據(jù)和資源文件,通過aapt工具捆綁成一個(gè)Android包,歸檔 文件以.apk為后綴。這個(gè)文件是分發(fā)應(yīng)用程序和安裝到移動(dòng)設(shè)備的中介或工具,用戶下載這個(gè)文件到他們的設(shè)備上。一個(gè).apk文件中的所有代碼被認(rèn)為是一 個(gè)應(yīng)用程序。
aapt:aapt是Android Asset Packaging Tool的首字母縮寫,這個(gè)工具包含在SDK的tools/目錄下。查看、創(chuàng)建、更新與zip兼容的歸檔文件(zip、jar、apk)。它也能將資源文件編譯成二進(jìn)制包。
盡管你可能不會(huì)經(jīng)常直接使用appt,但是構(gòu)建腳本(build scripts)和IDE插件會(huì)使用這個(gè)工具打包apk文件,構(gòu)成一個(gè)Android應(yīng)用程序。
如需更詳細(xì)的使用細(xì)節(jié),打開一個(gè)終端,進(jìn)入tools/目錄下,運(yùn)行命令:
Linux或Mac操作系統(tǒng):./aapt
Windows:aapt.exe
注意:tools/目錄是指android SDK目錄下的/platforms/android-X/tools/
在許多方面,每個(gè)Android應(yīng)用程序生活在它自己的世界:
- 默認(rèn)情況下,每一個(gè)應(yīng)用程序運(yùn)行在它自己的Linux進(jìn)程中。當(dāng)應(yīng)用程序中的任何代碼需要執(zhí)行時(shí),Android將啟動(dòng)進(jìn)程;當(dāng)它不在需要和系統(tǒng)資源被其他應(yīng)用程序請求時(shí),Android將關(guān)閉進(jìn)程。
- 每個(gè)應(yīng)用程序都有他自己的Java虛擬機(jī)(VM),因此應(yīng)用程序代碼獨(dú)立于其他所有應(yīng)用程序的代碼運(yùn)行。
- 默認(rèn)情況下,每個(gè)應(yīng)用程序分配一個(gè)唯一的Linux用戶的ID。權(quán)限設(shè)置為每個(gè)應(yīng)用程序的文件僅對用戶和應(yīng)用程序本身可見——雖然也有一些方法可以暴露他們給其他應(yīng)用程序。
有可能設(shè)置兩個(gè)應(yīng)用程序共享一個(gè)用戶ID,這種情況下,他們能夠看到對方的文件。為了節(jié)省系統(tǒng) 資源,具有相同ID的應(yīng)用程序也可以安排在同一個(gè)Linux進(jìn)程中,共享同一個(gè)VM。
2、應(yīng)用程序組件
Android的一個(gè)主要特點(diǎn)是,一個(gè)應(yīng)用程序可以 利用其他應(yīng)用程序的元素(假設(shè)這些應(yīng)用程序允許的話)。
例如,如果你的應(yīng)用程序需要顯示一個(gè)圖像的滾動(dòng)列表,且其他應(yīng)用程序已經(jīng)開發(fā)了一個(gè)合適的滾動(dòng)條并 可以提供給別的應(yīng)用程序用,你可以調(diào)用這個(gè)滾動(dòng)條來工作,而不用自己開發(fā)一個(gè)。
你的應(yīng)用程序不用并入其他應(yīng)用程序的代碼或鏈接到它。相反,當(dāng)需求產(chǎn)生時(shí)它 只是啟動(dòng)其他應(yīng)用程序塊。對于這個(gè)工作,當(dāng)應(yīng)用程序的任何部分被請求時(shí),系統(tǒng)必須能夠啟動(dòng)一個(gè)應(yīng)用程序的進(jìn)程,并實(shí)例化該部分的Java對象。
因此,不像其他大多數(shù)系統(tǒng)的應(yīng)用程序,Android應(yīng)用程序沒有一個(gè)單一的入口點(diǎn)(例如,沒有main()函數(shù))。相反,系統(tǒng)能夠?qū)嵗瓦\(yùn)行需要幾個(gè)必要的組 件。有四種類型的組件:
- 活動(dòng)(Activities)
- 服務(wù)(Services)
- 廣播接收者(Broadcast receivers)
- 內(nèi)容提供者(Content providers)
然而,并不是所有的應(yīng)用程序都必須包含上面的四個(gè)部分,你的應(yīng)用程序可以由上面的一個(gè)或幾個(gè)來 組建。當(dāng)你決定使用以上哪些組件來構(gòu)建Android應(yīng)用程序時(shí),你應(yīng)該將它們列在AndroidManifest.xml文件中,在這個(gè)文件中你可以聲 明應(yīng)用程序組件以及它們的特性和要求。關(guān)于AndroidManifest.xml在Android工程項(xiàng)目的目錄結(jié)構(gòu)的 1.6、AndroidManifest.xml簡單介紹了一下,你可以參考一下。
2.1、活動(dòng)(Activities)
一個(gè)活動(dòng)表示一 個(gè)可視化的用戶界面,關(guān)注一個(gè)用戶從事的事件。例如,一個(gè)活動(dòng)可能表示一個(gè)用戶可選擇的菜單項(xiàng)列表,或者可能顯示照片連同它的標(biāo)題。一個(gè)文本短信應(yīng)用程序 可能有一個(gè)活動(dòng),顯示聯(lián)系人的名單發(fā)送信息;第二個(gè)活動(dòng),寫信息給選定的聯(lián)系人;其他活動(dòng),重新查看舊信息或更改設(shè)置。雖然他們一起工作形成一個(gè)整體的用 戶界面,但是每個(gè)活動(dòng)是獨(dú)立于其他活動(dòng)的。每一個(gè)都是作為Activity基類的一個(gè)子類的實(shí)現(xiàn)。
android.app.Activity 類:因?yàn)閹缀跛械幕顒?dòng)(activities)都是與用戶交互的,所以Activity類關(guān)注創(chuàng)建窗口,你可以用方法 setContentView(View)將自己的UI放到里面。然而活動(dòng)通常以全屏的方式展示給用戶,也可以以浮動(dòng)窗口或嵌入在另外一個(gè)活動(dòng)中。有兩個(gè) 方法是幾乎所有的Activity子類都實(shí)現(xiàn)的:onCreate(Bundle):初始化你的活動(dòng)(Activity),比如完成一些圖形的繪制。最重要的是,在這個(gè)方法里你通常將用布局資源 (layout resource)調(diào)用setContentView(int)方法定義你的UI,和用findViewById(int)在你的UI中檢索你需要編程地 交互的小部件(widgets)。setContentView指定由哪個(gè)文件指定布局(main.xml),可以將這個(gè)界面顯示出來,然后我們進(jìn)行相關(guān) 操作,我們的操作會(huì)被包裝成為一個(gè)意圖(Intent),然后這個(gè)意圖對應(yīng)有相關(guān)的activity進(jìn)行處理。
onPause():處理當(dāng)離開你的活動(dòng)時(shí)要做的事情。最重要的是,用戶做的所有改變應(yīng)該在這里提交(通常ContentProvider保存數(shù)據(jù))。
一個(gè)應(yīng)用程序可能只包含一個(gè)活動(dòng),或者像剛才提到的短信應(yīng)用,它可能包含幾個(gè)活動(dòng)。這些活動(dòng)是什么,以及有多少,當(dāng)然這取決于它的應(yīng)用和設(shè)計(jì)。一般來講, 當(dāng)應(yīng)用程序被啟動(dòng)時(shí),被標(biāo)記為第一個(gè)的活動(dòng)應(yīng)該展示給用戶。從一個(gè)活動(dòng)移動(dòng)到另一個(gè)活動(dòng)由當(dāng)前的活動(dòng)完成開始下一個(gè)。
每一個(gè)活動(dòng)都有一個(gè)默認(rèn)的窗口。一般來講,窗口會(huì)填滿整個(gè)屏幕,但是它可能比屏幕小或浮在其他窗口上。一個(gè)活動(dòng)還可以使用額外的窗口——例如彈出式對話框,或當(dāng)一用戶選擇屏幕上一個(gè)特定的項(xiàng) 時(shí)一個(gè)窗口顯示給用戶重要的信息。
窗口的可視內(nèi)容是由繼承自View基類的一個(gè)分層的視圖—對象提供。每個(gè)視圖控件是窗口內(nèi)的一個(gè)特定的矩形空間。父視圖包含和組織子女視圖的布局。
葉子視圖(在分層的底層)繪制的矩形直接控制和響應(yīng)用戶的操作。因此,一個(gè)視圖是活動(dòng)與用戶交互發(fā)生的地方。例如,一個(gè)視圖可能顯示一個(gè)小的圖片和當(dāng)用戶點(diǎn)擊圖片時(shí)發(fā)起一個(gè)行為。
Android有一些現(xiàn)成的視圖你可以使用,包括按鈕(buttons)、文本域(text fields)、滾動(dòng)條(scroll bars)、菜單項(xiàng)(menu items)、復(fù)選框(check boxes)等等。通過Activity.setContentView() 方法放置一個(gè)視圖層次在一個(gè)活動(dòng)窗口中。內(nèi)容視圖(content view)是層次結(jié)構(gòu)的根視圖對象。層次結(jié)構(gòu)如下圖所示:
圖1、視圖的層次結(jié)構(gòu)
Activity.setContentView() 方法:public void setContentView (int layoutResID):根據(jù)布局資源設(shè)置活動(dòng)的界面。 資源將被夸大,添加布局資源文件中所有的最高層的視圖( top-level views )到活動(dòng).
2.2、 服務(wù)(Services)
一個(gè)服務(wù)沒有一個(gè)可視化用戶界面,而是在后臺(tái)無期限地運(yùn)行。例如一個(gè)服務(wù)可能是播放背景音樂而用戶做其他一些事情,或者它可能從 網(wǎng)絡(luò)獲取數(shù)據(jù),或計(jì)算一些東西并提供結(jié)果給需要的活動(dòng)(activities)。每個(gè)服務(wù)都繼承自Service基類。
每個(gè)服務(wù)類在AndroidManifest.xml中有相應(yīng)的<service>聲明。服務(wù)可以通過Context.startService()和Context.bindService()啟動(dòng)。
一個(gè)典型的例子是一個(gè)媒體播放器播放一個(gè)播放列表中的歌曲。該播放器應(yīng)用程序?qū)⒖赡苡幸粋€(gè)或多個(gè)活動(dòng)(activities),允許用戶選擇歌曲和開始播 放。然而,音樂播放本身不會(huì)被一個(gè)活動(dòng)處理,因?yàn)橛脩粝M3忠魳防^續(xù)播放,當(dāng)用戶離開播放器去做其他事情時(shí)。
為了保持音樂繼續(xù)播放,媒體播放器活動(dòng)可以啟動(dòng)一個(gè)服務(wù)運(yùn)行在后臺(tái)。系統(tǒng)將保持音樂播放服務(wù)運(yùn)行,甚至媒體播放器離開屏幕時(shí)??梢赃B接到(綁定到)一個(gè)持續(xù)運(yùn)行的服務(wù)(并啟動(dòng)服務(wù),如果它尚未運(yùn) 行)。
連接之后,你可以通過服務(wù)暴露的接口與服務(wù)交流。對于音樂服務(wù),這個(gè)接口可以允許用戶暫停、倒帶、停止和重新播放。像活動(dòng)(activities) 和其他組件一樣,服務(wù)(services)運(yùn)行在應(yīng)用程序進(jìn)程中的主線程中。因此,他們將不會(huì)阻止其他組件或用戶界面,他們往往產(chǎn)生其他一些耗時(shí)的任務(wù) (如音樂播放)。
2.3、廣播接收者(Broadcast receivers)
一個(gè)廣播接收者是這樣一個(gè)組件,它不做什么事,僅是接受廣播公告并作出相應(yīng)的反應(yīng)。許多廣播源自于系統(tǒng)代碼,例如公告時(shí)區(qū)的改變、電 池電量低、已采取圖片、用戶改變了語言偏好。
應(yīng)用程序也可以發(fā)起廣播,例如為了他其他程序知道某些數(shù)據(jù)已經(jīng)下載到設(shè)備且他們可以使用這些數(shù)據(jù)。一個(gè)應(yīng)用程序可以有任意數(shù)量的廣播接收者去反應(yīng)任何它認(rèn)為重要的公告。所有的接受者繼承自BroadcastReceiver基類。
BroadcastReceiver類:是接受sendBroadcast()發(fā)送的意圖(intents)的基類。可以用Context.registerReceiver()動(dòng)態(tài)地注冊這個(gè) 類的實(shí)例,或者通過AndroidManifest.xml中<receiver>標(biāo)簽靜態(tài)發(fā)布。注意:如果你在 Activity.onResume() 注冊一個(gè)接受者,你應(yīng)該在Activity.onPause()注銷它。因?yàn)楫?dāng)暫停時(shí)你不會(huì)收到意圖,注銷它將削減不必要的系統(tǒng)開銷。不要在 Activity.onSaveInstanceState()中注銷它,因?yàn)樗鼘⒉粫?huì)被調(diào)用,如果用戶移動(dòng)到先前的堆棧。
有兩種主要的可接受廣播類型:
正常廣播(由Context.sendBroadcast發(fā)送)是完全異步的。所有的廣播接收者以無序方式運(yùn)行,往往在同一時(shí)間接收。這樣效率較高,但是意味著接受者不能使用結(jié)果或終止廣播數(shù)據(jù)傳播。
有序廣播(由Context.sendOrderedBroadcast發(fā)送)一次傳遞給一個(gè)接收者。由于每個(gè)接收者依次執(zhí)行,因此它可以傳播到下一個(gè)接 收器,也可以完全終止傳播以便他不會(huì)傳遞給其他接收者。接收者的運(yùn)行順序可由匹配的意圖過濾器(intent-filter)的 android:priority屬性控制。
廣播接收者不顯 示一個(gè)用戶界面。然而,它們啟動(dòng)一個(gè)活動(dòng)去響應(yīng)收到的信息,或者他們可能使用NotificationManager去通知用戶。通知可以使用多種方式獲 得用戶的注意——閃爍的背光、振動(dòng)設(shè)備、播放聲音等等。典型的是放在一個(gè)持久的圖標(biāo)在狀態(tài)欄,用戶可以打開獲取信息。
2.4、內(nèi)容提供者(Content providers)
內(nèi)容提供者(content provider)使一個(gè)應(yīng)用程序的指定數(shù)據(jù)集提供給其他應(yīng)用程序。
這些數(shù)據(jù)可以存儲(chǔ)在文件系統(tǒng)中、在一個(gè)SQLite數(shù)據(jù)庫、或以任何其他合理的方式。 內(nèi)容提供者繼承自ContentProvider 基類并實(shí)現(xiàn)了一個(gè)標(biāo)準(zhǔn)的方法集,使得其他應(yīng)用程序可以檢索和存儲(chǔ)數(shù)據(jù)。然而,應(yīng)用程序并不直接調(diào)用這些方法。相反,替代的是它們使用一個(gè) ContentResolver對象并調(diào)用它的方法。ContentResolver能與任何內(nèi)容提供者通信,它與提供者合作來管理參與進(jìn)來的進(jìn)程間的通信。
內(nèi)容提供者是Android 應(yīng)用程序的主要組成部分之一,提供內(nèi)容給應(yīng)用程序。他們封裝數(shù)據(jù)且通過單個(gè)ContentResolver接口提供給應(yīng)用程序。只有需要在多個(gè)應(yīng)用程序間 共享數(shù)據(jù)是才需要內(nèi)容提供者。例如,通訊錄數(shù)據(jù)被多個(gè)應(yīng)用程序使用,且必須存儲(chǔ)在一個(gè)內(nèi)容提供者中。如果你不需要在多個(gè)應(yīng)用程序間共享數(shù)據(jù),你可以直接使 用SQLiteDataBase。當(dāng)ContentResolver發(fā)出一個(gè)請求時(shí),系統(tǒng)檢查給定的URI的權(quán)限并傳遞請求給內(nèi)容提供者注冊。內(nèi)容提供者能理解URI想要的東西。UriMatcher 類用于幫組解析URIs。
需要實(shí)現(xiàn)的方法主要如下:
query(Uri, String[], String, String[], String) 返回?cái)?shù)據(jù)給調(diào)用者
insert(Uri, ContentValues) 插入數(shù)據(jù)到內(nèi)容提供者
update(Uri, ContentValues, String, String[]) 更新內(nèi)容提供者已存在的數(shù)據(jù)
delete(Uri, String, String[]) 從內(nèi)容提供者中刪除數(shù)據(jù)
getType(Uri) 返回內(nèi)容提供者中的MIME 類型數(shù)據(jù)
更多的關(guān)于ContentResolver信息,請查看相關(guān)文檔。每當(dāng)有一個(gè)應(yīng)該由特定組件處理的請求,Android可以確保該組件的應(yīng)用程序正在運(yùn)行,如果沒有就啟動(dòng)它,而且一個(gè)適當(dāng)?shù)慕M件實(shí)例可用,如果沒有就創(chuàng)建。