天天看點

Android Application Foundamentals(yaozq翻譯,僅供參考)

QuickView

Android軟體是由一個或多個應用程式元件組成的,這些元件有activities、services、content provider和broadcast receivers。

每一個元件在整個程式的behavior中扮演着重要角色,而且每一個元件都可以被單獨的激活(activated),甚至可以由其他的程式激活。

在manifest檔案中必須要聲明程式中所有的元件和必要的條件,比如需要的最低Android平台版本或者硬體配置。

不需要編碼的程式資源(圖檔、字元串、布局檔案等)必須要為不同的裝置配置(比如為不同的語言準備不同的字元串,為不同的螢幕尺寸準備不同的布局檔案)準備好。

Android軟體是用Java程式設計語言編寫的。Android SDK tools對代碼和資源與資料檔案一起編譯成一個以.apk為字尾的Android包。在一個單獨的.apk檔案中的所有代碼被認為一個程式,并且是一個Android系統的裝置可以安裝的程式。

一旦程式在一個裝置上被安裝,每一個Android軟體都存在于自己的安全沙箱中:

Android系統是一個多使用者的Linux系統,系統中的每一個程式都是一個不同的使用者。

預設情況下,系統會為每一個程式配置設定一個唯一的Linux使用者ID(這個ID隻是為系統所使用,并不為程式所知)。系統為程式中的檔案設定一定的權限,這樣隻有相同使用者ID的程式可以通路那些檔案。

Android系統中,每一個程序都有自己的虛拟機(VM),這樣每一個程式的代碼都單獨的運作。

預設情況下,每一個程式都運作在自己的Linux程序中。當程式中的任意一個元件被執行的時候,Android系統會啟動元件所在的程式的程序,當這個系統不再需要這個程序,且為了為其他程式節省記憶體的時候,便會關閉這個程序。

通過這種方式,Android系統便實作了least privilege準則。那就是,在預設情況下,每一個程式隻能通路有工作要做的元件。這就建立了一種非常安全的環境,在這種環境中,程式不能通路沒有授予權限通路的系統的其他部分。

然而,在Android系統中還設有辦法去和其他的程式共享資料和去通路系統服務:

隻要程式有相同的Linux使用者ID,則他們之間就是可以互相通路對方的檔案的,而讓兩個程式具有相同的Linux使用者ID是可能的。為了儲存系統資源,具有相同使用者ID的程式甚至可以在相同的Linux繼承中運作,并共享同一個VM(當然還有個條件就是這兩個程式必須有相同的證書(cetificate))。

一個程式可以要求一定的權限來通路裝置的資料,比如使用者的聯系人、短資訊、SD卡(the mountable storage)、照相機、藍牙等等。這些所有的權限必須在使用者安裝的時候被使用者所承認。

上面講了關于Android軟體是如何在系統中存在的基本内容。剩下的内容将介紹的内容包括:定義你程式的核心架構元件;在manifest檔案中為你的程式聲明你的元件和裝置必須具備的特點;獨立于程式代碼的資源,并為不同的裝置最優化你的代碼。

程式元件(Application Component)

程式元件是構成Android程式的基本元素。每一個元件都是系統可以進入你的程式的入口點。對使用者來說并不是所有的元件都是入口點,但是每一個元件都已自己的實體存在,并扮演一個特定的角色,那就是每一個都是可以幫助你定義你的程式特征的元素。

在Android系統中,共有四種 不同的元件。每一個元件都有自己獨特的作用和不同的生命周期,這個生命周期就是定義了元件是如何建立 和被銷毀的一個過程。

Activities

一個Activity就是一個擁有使用者界面的螢幕。比如,一個email程式可能包含一個用于顯示新郵件的activity,一個用于編寫郵件的activity,一個用于讀取郵件的activity。雖然這些activities work together,讓使用者形成了一個連續的使用者體驗,但是每一個activity都是獨立于其他activity的。 這樣,隻要這個email程式允許,一個不同的程式就可以啟動這些activities中的一個activity。比如,為了讓使用者分享一張圖檔,一個camera程式就可以啟動一個編寫新郵件的activity。

一個activity擴充子Activity類,你可以通過Activities developer guide了解更多。

Services

一個service是一個為了執行一個長時間的操作或者為遠端程序共多的而在背景運作的元件。一個service并沒有使用者界面。比如,當使用者執行不同程式的時候,一個用于播放音樂的service可以在背景一直運作,或者為了不堵塞使用者與activity繼續互動時,一個service可以用于從網際網路上下載下傳資料。一個其他的元件,比如activity,可以啟動這個元件,或者為了與這個元件進行互動來綁定這個service。

一個service應該擴充子Service類,并且你可以通過Services developer guide來學習更多的關于service的知識。

Content providers

一個content provider主要用于共享資料。你可以把資料存在檔案中、一個SQLite資料庫中、網際網路上、或者其他的你的程式可以通路的persistent storage location。通過一個content provider,其他的程式可以查詢甚至修改資料(隻要這個content provider允許)。比如,Android系統就為了處理使用者的聯系人資訊而提供了一個content provider。這樣的話,擁有适當權限的任何程式都可以查詢content provider共享的資料(比如ContactsContract.Data),來讀和寫 關于一個特定聯系人的資訊。

Content  provider對于你的程式私有的資料的讀寫也是很有用的。比如,那個Note Pad例子就是使用content provider來儲存筆記。

Broadcast receiver

一個broadcast receiver是一個可以對在整個系統中傳播的廣播做出響應的元件。許多像螢幕關閉、電池電量太少、拍了一張照片等這種廣播是有系統發出的。一個程式一個可以發送廣播,比如為了讓其他的程式知道一些資料已經被下載下傳完成并可以被使用時,就可以發送一個廣播。雖然broadcast receiver并沒有一個使用者界面,但是它們會建立一個status bar notification來告知使用者一個廣播時間發生了。更常見的情形是,一個broadcast receiver隻是用與其他元件進行通信,并隻做很少的工作。比如,一個broadcast receiver可能隻是啟動一個service。

Android系統設計的一個獨特方面是任何的一個程式都可以啟動另一程式的元件。比如,你想讓你的程式可以使用照相機拍照,如果已經有了實作這種功能的程式并且你你的程式能使用它(有權限),那麼你就沒有再要再寫一個新的Activity來實作這個功能。你的程式不需要包含或者連結這個拍照程式。相反,你隻需要在你的程式中打開這個拍照程式中的實作拍照功能的Activity。當拍完之後,拍好的照片甚至會自動傳回給你的程式。者對于使用者來說,就好像是想拍照功能的程式就是你的這個程式的一部分一樣。

當系統啟動一個元件之後,如果這個元件所在的程式之前沒有運作的話,系統會自動開始這個程式的程序,并初始化這個元件所需要的相關類。比如,你的程式開啟了一個拍照功能程式的Activity,這時系統會啟動這個Activity所在的程式,是以這個Activity運作在拍照功能的程式當中,而不是在你的程式中。是以,不像其他作業系統的中的程式一樣,Android程式沒有一個單獨的入口點(比如沒有我們常見的main()函數)。   

因為系統中的程式運作在自己的獨立程序中,并且程式中的檔案都有自己的限制其他程式通路的權限,是以,你的程式不能直接激活其他程式中的元件。但是Android系統就可以。具體是這樣的實作的,為了激活(activate)其他程式中的元件,你必須向系統發送一個消息來詳細說明你要啟動其他元件的意圖,這樣系統才會為你激活這個元件。  

激活元件(Activating Components)

四大元件中的三個元件——activities、services和broadcast receiver——是由一種叫intent的異步消息來激活的。這些intents在運作時(runtime)将這些屬于你的程式或不同程式的單獨的元件綁定在一起(bind),你可以把這些intents看作是需要其他元件的action的messengers。

一個intent就是一個Intent對象,這個intent定義了一種可以激活(activate)某個特定元件或者某種特定類型的元件,這兩種情況分别對應兩種intent的定義方式或者顯示的或者隐式的。

對于activities和services,一個intent定義了要執行的操作(action)(比如,要“view”或者“send”什麼)和要操作的資料的URI。比如,一個intent可能會為一個activity傳遞一個請求來展示一張圖檔或者打開一個網頁。有時,你可以啟動一個activity來得到傳回的結果,在這個例子中這個activity的傳回的結果也是一個Intent(比如,你可以發送一個intent讓使用者選擇一個personal contact并傳回給你——這個傳回的intent就包含了一個指向使用者選擇的聯系人的URI)。(關于activity和service的啟動方式,下面将介紹。)

對于廣播接收者來說,intent隻是簡單的定義了要廣播的内容(比如,一個用以表明電池電量很低的廣播僅包含了一個表明電池電量很低的字元串)。

最後一種元件類型content provider并不是由intent來激活的(activate)。而是由接收到ContentResolver的請求時激活的。。。。

它們都各自有自己的方法來激活相應的元件:

你可以通過傳遞一個Intent給startActivity()或startActivityForResult()啟動一個activity(或者給他一些新的要做的内容)。使用startActivityForResult()你将得到一個傳回結果。

你可以通過傳遞一個Intent給startService()來start一個service(或者給一個正在運作的service一些新的指令(instructions))。或者你可以通過把一個Intent傳遞給bindService()來綁定一個service。

你可以通過傳遞一個Intent給諸如sendBroadcast()、sendOrderedBroadcast()或者sendStickyBroadcast()等方法來初始化一個廣播。

你可以通過調用ContentResolver的query()方法來執行一次content provider的查詢操作。

更多的關于intent的内容,可以參看文檔中的Intents and Intent Filters。更多的關于激活特定元件的内容可以參看文檔中的:Activities、Services、BroadcastReceiver、Content Providers。

關于Manifest檔案

在Android系統可以啟動一個應用程式元件之前,Android系統必須通過讀取這個程式的AndroidManifest.xml(即manifest檔案)檔案來确定要啟動的元件存在。你的程式必須在這個manifest檔案聲明用到的所有的元件,并且這個manifest檔案必須在項目的根目錄下。

另外,這個manifest檔案還聲明一些其他的東西,比如:

(1)确定這個程式需要的所有權限,比如Internet通路權限或者讀取使用者聯系人權限。

(2)聲明這個運作這個程式所需要的最低API版本,這個可以根據開發該程式所使用的API版本。

(3)聲明該程式所需要的硬體或軟體特征(features),比如照相機、藍牙服務或者多點觸屏。

(4)聲明該程式需要連結(link against)的API庫(不是Andorid的framework APIs),比如Google Maps library。

(5)等等。

元件聲明(Declaring components)

Manifest檔案的首要任務就是通知系統關于程式中要使用的元件。比如,一個manifest檔案可以用如下的方式來聲明一個activity:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:icon="@drawable/app_icon.png" ... >
<activity android:name="com.example.project.ExampleActivity"
                  android:label="@string/example_label" ... >
</activity>
 ...
</application>
</manifest>      

在<application>元素中,android:icon屬性用于指定一個用于标示該程式的icon。

在<activity>元素中,android:name屬性用于确定這個擴充自Activity的子類的全路徑名,android:label屬性用于标示這個activity的對于使用者可見的label。

你必須要用以下方式來聲明你的程式元件:

activities:<activity>标簽

services:<service>标簽

broadcast receiver:<receiver>标簽

content providers:<provider>标簽

如果程式中用到activities、services和content providers,你沒有在manifest檔案中聲明,那麼這些元件将不會被系統知道,結果就是你的程式不能運作。然而,broadcast receiver既可以在manifest檔案中聲明也可以在代碼中動态建立(BroadcastReceiver),并通過調用registerReceiver()在系統中注冊。

更多關于怎樣為你的程式建構manifest檔案,請參看文檔The AndroidManifes.xml檔案。

聲明元件的能力(Declaring component capabilities)

正如在上面Activating Components中讨論的那樣,你可以使用一個Intent來啟動activities、services和broadcast receiver。你可以通過在intent中注明目标元件的名字(使用的是元件的類名)來顯示的啟動元件。然而,intents真正強大的地方在與關于intent的actions的概念。通過intent的actions,你可以簡單的描述你要執行的操作的類型(并且可以有選擇的描述你要處理的資料),可以允許系統在device中找到這個元件并啟動它。如果有多個元件可以執行intent中描述的action,這時使用者就可以選擇一個來執行。

系統可以識别能對某intent做出反應的方式是通過将接收到的intent和裝置中其他程式的manifest檔案的intent filters進行比較實作的。

當你在程式的manifest檔案中聲明一個元件之後,你可以有選擇包含intent filters,這些intent filters表明了元件對接收自其他程式的intent做出反應的能力(capabilities)。你可以通過添加一個<intent-filter>元素作為a child of the component's declaration element來為你的程式聲明一個intent filter。

比如,在一個郵件程式中的一個activity可以編寫新的郵件,這樣的話你就需要在manifest檔案中來聲明一個intent filter來對“發送”intent響應(為了發送郵件)。這樣,在你的程式中,一個activity就可以建立一個發送intent(ACTION_SEND),這樣當你調用startaActivity()時,系統就會比對郵件程式中的發送activity并啟動它。

更多關于建立intent filters的内容,可以參看Intents and Intent Filter文檔。

聲明運作程式所需的條件(Declaring application requirements)

Andorid系統可以支援很多不同的裝置,并且這些裝置的性能特征并不相同。為了防止你的程式被安裝在不能正常運作你的程式的較低android系統版本上,通過在manifest檔案中聲明你的程式支援的裝置和軟體,便變得尤其重要起來。大多數的這些聲明僅是一些資訊,而系統并不會讀取它們,但是其他的服務比如Android Market卻會閱讀這些聲明來幫助通過通過自己的裝置搜尋軟體的使用者過濾軟體。

比如,你的程式需要照相機,并且使用的Android2.1的APIs,那麼你就必須在你的manifest檔案中聲明這些需要。這樣的話,在Android Market上,沒有照相機或者Android系統版本低于2.1将不能安裝你的程式。

然而,如果你的程式不需要照相機,你仍可以聲明你需要照相機。這種情況下,你的程式必須在運作時做一下檢查,來檢查這個裝置是否含有照相機,如果沒有照相機可用,則系統将會使使用照相機的相關程式不能用。

下面是一些你在設計和開發你的程式時,必須要考慮的關于裝置的一些重要方面:

螢幕大小和分辨率(Screen size and density)

為了根據螢幕的類型進行分類,Android定義了兩個特征:螢幕大小和分辨率。

螢幕尺寸有: small, normal, large, and extra large

螢幕分辨率類型有:low density, medium density, high density, and extra high density

預設情況下,你的程式可以相容所有的螢幕尺寸和分辨率,因為Android系統對你的程式的UI布局和image資源做了适當的調整。然而,you should create specialized layouts for certain screen sizes and provide specialized images for certain densities, using alternative layout resources, and by declaring in your manifest exactly which screen sizes your application supports with the 

<supports-screens>

 element.

輸入方式(Input configurations)

很多裝置有不同類型的輸入方式,比如a hardware keyboard, a trackball, or a five-way navigation pad。如果你的程式需要某特定形式的輸入方式,則你必須在manifes檔案中使用<uses-configuration>标簽來聲明。不過這種情況是比較少的。

裝置配置(Device features):有許多硬體或軟體并不全在Android系統的裝置上,比如,一個照相機、光線傳感器、特定版本的OpenGL,或者螢幕的保真度(fidelity)。你在任何條件下都不能假定Android裝置具備某種特性(feature)(當然得除掉Android标準庫的情況),是以如果你的程式使用了某feature,則你必須使用<uses-feature>标簽來聲明。

平台版本(Device features):

程式資源檔案(Application Resources)

一個Android程式不隻是由代碼組成的,它還需要獨立于源碼的資源,比如圖檔、音頻檔案、和程式相關的可使用的任何資源。比如,你應該定義動畫(animations)、菜單(menus)、樣式(styles)、顔色(colors)、布局檔案。使用這些資源可以在不需要改動代碼的情況下,通過提供各種可用的資源(by providing sets of alternative resources),來更容易的更新你的程式(update characteristics of your application),讓你為不同配置(比如不同語言或者螢幕尺寸)的Android裝置來最優化你的程式。

對于你在程式中包含的每一個資源,SDK build tools都會定義一個唯一的整形ID,你可以使用這個ID來引用你的代碼中或在XML中定義的資源。比如,你的程式包含一張名為logo.png圖檔資源(儲存在res/drawable目錄下),這是SDK tools便會生成一個叫R.drawable.logo的資源ID,這樣你就可以在使用者接口(user interface)中通過使用這個ID來引用這張圖檔。

Android系統提供這種獨立于代碼的資源的一個重要方面就是可以讓你為不同配置的設配都提供可用的資源(provide alternative resources)。比如,通過在XML檔案中定義UI字元串,你就可以把這些字元串翻譯成其他語言,并把這些字元串儲存在單獨的檔案中。這樣,根據你添加的資源目錄的名字(比如使用res/values-fr表示法語字元串值)和使用者的語言設定,Android系統便會向你的UI中提供适合使用者的語言。

對于你提供的各種可用資源,Android系統支援多種不同的限定詞(qualifiers)。這個限定詞是你根據這些資源可以被哪些裝置配置(configuration)而以你的資源目錄的名義定義的(in the name of your resource directories)一個比較短的字元串。另一例子是,你應該根據裝置的平米方向和尺寸來為你的activities建立不同的布局檔案。比如,如果裝置的螢幕是豎屏的(in portrait orientation),這是你可能需要一個buttons是vertical的布局,如果螢幕是寬屏時(in landscape orientation),布局中的buttons就應該水準放齊。為了根據裝置螢幕方向二改變布局,你可以定義兩種不同的布局,并根據布局檔案的目錄名來使用合适的限定詞。這樣系統便會根據當期裝置的方向來自動的提供合适的布局檔案。

更多的關于你的程式中可以包含的資源和如何為不同配置的裝置提供可用的資源,可以參看Appication Resources developer guide。

繼續閱讀