——成功屬於耐得住寂寞的人,接下來幾篇將講述Android應用程式的原理及術語,可能會比較枯燥。如果能夠靜下心來看,相信成功將屬於你。
引言
為了後面的例子做準備,本篇及接下來幾篇將介紹Android應用程式的原理及術語,這些也是作為一個Android的開發人員必須要瞭解,且深刻理解的東西。本篇的主題如下:
- 1、應用程式基底礎
- 2、應用程式組件
- 2.1、活動(Activities)
- 2.2、服務(Services)
- 2.3、廣播接收者(Broadcast receivers)
- 2.4、內容提供者(Content providers)
因為這些內容比較理論,且沒有用例子來說明,看上去會比較枯燥,我就把這幾篇寫得算比較短,方便大家吸收。
1、應用程式基底礎
Android應用程式是用Java程式設計語言寫的。編譯後的Java代碼——包括應用程式要求的任何資料和資源檔,通過aapt工具捆綁成一個Android包,歸檔檔案以.apk為尾碼。這個檔案是分發應用程式和安裝到行動裝置的中介或工具,使用者下載這個檔案到他們的裝置上。一個.apk檔案中的所有代碼被認為是一個應用程式。
aapt:
aapt是Android Asset Packaging Tool的首字母縮寫,這個工具包含在SDK的tools/目錄下。查看、建立、更新與zip相容的歸檔檔案(zip、jar、apk)。它也能將資源檔編譯成二進位包。
儘管你可能不會經常直接使用appt,但是構建指令碼(build scripts)和IDE外掛程式會使用這個工具打包apk檔案,構成一個Android應用程式。
如需更詳細的使用細節,開啟一個終端,進入tools/目錄下,運行命令:
- Linux或Mac作業系統:./aapt
- Windows:aapt.exe
注意:tools/目錄是指android SDK目錄下的/platforms/android-X/tools/
在許多方面,每個Android應用程式生活在它自己的世界:
- 預設情況下,每一個應用程式運行在它自己的Linux進程中。當應用程式中的任何代碼需要執行時,Android將啟動進程;當它不在需要和系統資源被其他應用程式請求時,Android將關閉進程。
- 每個應用程式都有他自己的Java虛擬機器(VM),因此應用程式代碼獨立於其他所有應用程式的代碼運行。
- 預設情況下,每個應用程式分配一個唯一的Linux使用者的ID。使用權限設定為每個應用程式的檔案僅對使用者和應用程式本身可見——雖然也有一些方法可以暴露他們給其他應用程式。
有可能設定兩個應用程式共用一個使用者ID,這種情況下,他們能夠看到對方的檔案。為了節省系統資源,具有相同ID的應用程式也可以安排在同一個Linux進程中,共用同一個VM。
2、應用程式組件
Android的一個主要特點是,一個應用程式可以利用其他應用程式的元素(假設這些應用程式允許的話)。例如,如果你的應用程式需要顯示一個映像的滾動列表,且其他應用程式已經開發了一個合適的捲軸並可以提供給別的應用程式用,你可以調用這個捲軸來工作,而不用自己開發一個。你的應用程式不用併入其他應用程式的代碼或連結到它。相反,當需求產生時它只是啟動其他應用程式塊。
對於這個工作,當應用程式的任何部分被請求時,系統必須能夠啟動一個應用程式的進程,並執行個體化該部分的Java對象。因此,不像其他大多數系統的應用程式,Android應用程式沒有一個單一的進入點(例如,沒有main()函數)。相反,系統能夠執行個體化和運行需要幾個必要的組件。有四種類型的組件:
- 活動(Activities)
- 服務(Services)
- 廣播接收者(Broadcast receivers)
- 內容提供者(Content providers)
然而,並不是所有的應用程式都必須包含上面的四個部分,你的應用程式可以由上面的一個或幾個來組建。當你決定使用以上哪些組件來構建Android應用程式時,你應該將它們列在AndroidManifest.xml檔案中,在這個檔案中你可以聲明應用程式組件以及它們的特性和要求。關於AndroidManifest.xml在Android開發之旅:HelloWorld項目的目錄結構的1.6、AndroidManifest.xml簡單介紹了一下,你可以參考一下,下篇也將介紹它。
2.1、活動(Activities)
一個活動表示一個可視化的使用者介面,關注一個使用者從事的事件。例如,一個活動可能表示一個使用者可選擇的功能表項目列表,或者可能顯示照片連同它的標題。一個文本簡訊應用程式可能有一個活動,顯示連絡人的名單發送資訊;第二個活動,寫資訊給選定的連絡人;其他活動,重新查看舊資訊或更改設定。雖然他們一起工作形成一個整體的使用者介面,但是每個活動是獨立於其他活動的。每一個都是作為Activity基類的一個子類的實現。
android.app.Activity類:因為幾乎所有的活動(activities)都是與使用者互動的,所以Activity類關注建立視窗,你可以用方法setContentView(View)
將自己的UI放到裡面。然而活動通常以全屏的方式展示給使用者,也可以以浮動視窗或嵌入在另外一個活動中。有兩個方法是幾乎所有的Activity子類都實現的:
onCreate(Bundle):初始化你的活動(Activity),比如完成一些圖形的繪製。最重要的是,在這個方法裡你通常將用布局資源(layout resource)調用setContentView(int)方法定義你的UI,和用findViewById(int)在你的UI中
檢索你需要編程地互動的小組件(widgets)。setContentView
指定由哪個檔案指定布局(main.xml),可以將這個介面顯示出來,然後我們進行相關操作,我們的操作會被封裝成為一個意圖(Intent),然後這個意圖對應有相關的activity進行處理。
onPause()
:處理當離開你的活動時要做的事情。最重要的是,使用者做的所有改變應該在這裡提交(通常ContentProvider
儲存資料)。
一個應用程式可能只包含一個活動,或者像剛才提到的簡訊應用,它可能包含幾個活動。這些活動是什麼,以及有多少,當然這取決於它的應用和設計。一般來講,當應用程式被啟動時,被標記為第一個的活動應該展示給使用者。從一個活動移動到另一個活動由當前的活動完成開始下一個。
每一個活動都有一個預設的視窗。一般來講,視窗會填滿整個螢幕,但是它可能比螢幕小或浮在其他視窗上。一個活動還可以使用額外的視窗——例如彈出式對話方塊,或當一使用者選擇螢幕上一個特定的項時一個視窗顯示給使用者重要的資訊。
視窗的可視內容是由繼承自View基類的一個分層的視圖—對象提供。每個視圖控制項是視窗內的一個特定的矩形空間。父視圖包含和組織子女視圖的布局。葉子視圖(在分層的底層)繪製的矩形直接控制和響應使用者的操作。因此,一個視圖是活動與使用者互動發生的地方。例如,一個視圖可能顯示一個小的圖片和當使用者點擊圖片時發起一個行為。Android有一些現成的視圖你可以使用,包括按鈕(buttons)、文本域(text fields)、捲軸(scroll bars)、功能表項目(menu items)、複選框(check boxes)等等。
通過Activity.setContentView() 方法放置一個視圖層次在一個使用中視窗中。內容視圖(content view)是階層的根視圖對象。階層如所示:
圖1、視圖的階層
Activity.setContentView() 方法:public void setContentView (int layoutResID):根據布局資源設定活動的介面。 資源將被誇大,添加布局資源檔中所有的最高層的視圖( top-level views )到活動.
2.2、 服務(Services)
一個服務沒有一個可視化使用者介面,而是在後台無期限地運行。例如一個服務可能是播放背景音樂而使用者做其他一些事情,或者它可能從網路擴取資料,或計算一些東西並提供結果給需要的活動(activities)。每個服務都繼承自Service基類。
每個服務類在AndroidManifest.xml中有相應的聲明。服務可以通過Context.startService()和Context.bindService()啟動。
一個典型的例子是一個媒體播放器播放一個播放清單中的歌曲。該播放器應用程式將可能有一個或多個活動(activities),允許使用者選擇歌曲和開始播放。然而,音樂播放本身不會被一個活動處理,因為使用者希望保持音樂繼續播放,當使用者離開播放器去做其他事情時。為了保持音樂繼續播放,媒體播放器活動可以啟動一個服務運行在後台。系統將保持音樂播放服務運行,甚至媒體播放器離開螢幕時。
可以串連到(綁定到)一個持續啟動並執行服務(並啟動服務,如果它尚未運行)。串連之後,你可以通過服務暴露的介面與服務交流。對於音樂服務,這個介面可以允許使用者暫停、倒帶、停止和重新播放。
像活動(activities)和其他組件一樣,服務(services)運行在應用程式進程中的主線程中。因此,他們將不會阻止其他組件或使用者介面,他們往往產生其他一些耗時的任務(如音樂播放)。
2.3、廣播接收者(Broadcast receivers)
一個廣播接收者是這樣一個組件,它不做什麼事,僅是接受廣播公告並作出相應的反應。許多廣播源自於系統代碼,例如公告時區的改變、電池電量低、已採取圖片、使用者改變了語言偏好。應用程式也可以發起廣播,例如為了他其他程式知道某些資料已經下載到裝置且他們可以使用這些資料。
一個應用程式可以有任意數量的廣播接收者去反應任何它認為重要的公告。所有的接受者繼承自BroadcastReceiver基類。
BroadcastReceiver類:
是接受sendBroadcast()發送的意圖(intents)的基類。可以用Context.registerReceiver()動態地註冊這個類的執行個體,或者通過AndroidManifest.xml中標籤靜態發布。注意:如果你在Activity.onResume() 註冊一個接受者,你應該在Activity.onPause()登出它。因為當暫停時你不會收到意圖,登出它將削減不必要的系統開銷。不要在Activity.onSaveInstanceState()中登出它,因為它將不會被調用,如果使用者移動到先前的堆棧。
有兩種主要的可接受廣播類型:
- 正常廣播(由Context.sendBroadcast發送)是完全非同步。所有的廣播接收者以無序方式運行,往往在同一時間接收。這樣效率較高,但是意味著接受者不能使用結果或終止廣播資料傳播。
- 有序廣播(由Context.sendOrderedBroadcast發送)一次傳遞給一個接收者。由於每個接收者依次執行,因此它可以傳播到下一個接收器,也可以完全終止傳播以便他不會傳遞給其他接收者。接收者的運行順序可由匹配的意圖過濾器(intent-filter)的
android:priority
屬性控制。
廣播接收者不顯示一個使用者介面。然而,它們啟動一個活動去響應收到的資訊,或者他們可能使用NotificationManager
去通知使用者。通知可以使用多種方式獲得使用者的注意——閃爍的背光、震動裝置、播放聲音等等。典型的是放在一個持久的表徵圖在狀態列,使用者可以開啟擷取資訊。
2.4、內容提供者(Content providers)
內容提供者(content provider)使一個應用程式的指定資料集提供給其他應用程式。這些資料可以儲存在檔案系統中、在一個SQLite資料庫、或以任何其他合理的方式。內容提供者繼承自ContentProvider 基類並實現了一個標準的方法集,使得其他應用程式可以檢索和儲存資料。然而,應用程式並不直接調用這些方法。相反,替代的是它們使用一個ContentResolver對象並調用它的方法。ContentResolver能與任何內容提供者通訊,它與提供者合作來管理參與進來的進程間的通訊。
內容提供者是Android應用程式的主要組成部分之一,提供內容給應用程式。他們封裝資料且通過單個ContentResolver介面提供給應用程式。只有需要在多個應用程式間共用資料是才需要內容提供者。例如,通訊錄資料被多個應用程式使用,且必須儲存在一個內容提供者中。如果你不需要在多個應用程式間共用資料,你可以直接使用SQLiteDataBase。
當ContentResolver發出一個請求時,系統檢查給定的URI的許可權並傳遞請求給內容提供者註冊。內容提供者能理解URI想要的東西。UriMatcher 類用於幫組解析URIs。
需要實現的方法主要如下:
query(Uri, String[], String, String[], String)
返回資料給調用者
insert(Uri, ContentValues)
插入資料到內容提供者
update(Uri, ContentValues, String, String[])
更新內容提供者已存在的資料
delete(Uri, String, String[])
從內容提供者中刪除資料
getType(Uri)
返回內容提供者中的MIME 類型資料
更多的關於ContentResolver資訊,請查看相關文檔。
每當有一個應該由特定組件處理的請求,Android可以確保該組件的應用程式正在運行,如果沒有就啟動它,而且一個適當的組件執行個體可用,如果沒有就建立。