標籤:
官方文檔原文地址
應用程式原理
Android應用程式是通過Java程式設計語言來寫。Android軟體開發工具把你的代碼和其他資料、資源檔一起編譯、打包成一個APK檔案,這個文檔以.apk為尾碼,儲存了一個Android應用程式所有的內容,Android裝置通過它來安裝對應的應用。
一旦安裝到裝置上,每個Android應用程式就運行在各自獨立的安全沙箱中:
- Android系統是一個多使用者的Linux系統,每一個應用都是一個使用者。
- Android系統預設會給每個應用程式指派一個唯一的使用者ID(這個ID只被系統使用,應用並不瞭解)。系統給每個應用對應的所有檔案都設定了許可權,只有使用者ID正確的應用才能訪問。
- 每個進程都有它獨立的虛擬機器,因此一個應用程式代碼才能獨立運行,不受其他應用幹擾。
- 預設的,每個應用運行在各自獨立的Linux進程中。當一個應用中有一個組件需要執行時,系統就會開啟它的進程。當這個進程裡沒有活動或者系統記憶體不足需要關閉進程為其他應用回收記憶體時,會關閉這個進程。
每個應用運行在各自獨立的沙箱中,通過這樣的方式Android系統實現了最少許可權原則—-即每個應用預設只有訪問它工作需要使用的資源的許可權(譯者註:注意這裡是預設,很多情況下其實我們需要訪問其他應用的資源,這個時候就需要用到另外一個關鍵技術“進程通訊”)。這樣就建立了一個非常安全的環境,在這個環境下一個應用不能訪問那些它沒有許可權的檔案。
然而,系統還是提供了一些應用間共用資料和應用訪問系統服務的方式:
- 我們可以給兩個應用共用同樣的Linux使用者ID,那樣它倆就可以訪問彼此的檔案了。為了節省系統資源,有相同UID的應用可以運行在同一個Linux進程中、使用同一個虛擬機器,前提是這些應用必須有同樣的簽名。
- 一個應用可以請求一些訪問裝置資料的許可權,比如說使用者的連絡人、簡訊、SD卡、相機、藍芽等等。使用者可以決定是否授予應用這些許可權。
上面概述了關於Android應用在系統中如何存在的原理。下面將介紹:
- 構建應用的核心架構組件
- 在manifest檔案中為你的應用聲明組件和請求裝置特性
- 與代碼分開、讓你的應用在許多裝置配置下表現的儘可能優雅的資源
應用組件
應用組件是構建一個Android程式必備的模組。系統可以通過不同組件的組件來進入你的應用。不是所有的組件使用者都能看得到、摸得著,有些組件需要依靠其他組件才能啟動,但是它們又作為一個獨立個體存在,同時扮演著不同的角色協助你決定你的應用都有什麼行為。
應用組件有四種類型,每種類型都有其獨特的功能,同時還有決定其如何建立、銷毀的生命週期。
下面是四種不同類型的應用組件:
Activity
一個Activity代表了一個介面。比如說,一個電子郵件應用可能有一個現實新郵件列表的Activity,還有一個建立郵件的Activity,另外還有一個閱讀郵件的Activity。這些Activities一起工作群組成一個完整的電子郵件使用者體驗,同時每個Activity又是相互獨立的,因此其他應用可以調用上述幾個(如果這個電子郵件應用允許)。比如說一個相機應用為了讓使用者分享相片,可以直接啟動建立郵件的Activity。
Services
Service是一個運行在背景組件,常用來進行長耗時操作或者執行跨進程操作。Service不提供使用者介面。比如說,Service可以在使用者使用別的應用的時候後台播放音樂,或者也可以在不妨礙使用者互動的情況下,在後台從伺服器請求資料。其他組件,比如說Activity,可以開始Service,或者跟Service綁定從而可以發生互動。
Content Providers
Content provider 管理著一套可共用的應用資料。你可以把資料存到檔案系統、SQLite資料庫,網路或者其他任何你應用能訪問的可持久儲存的地方。通過content provider,其他應用可以查詢甚至修改資料(如果該content provider允許的話)。比如說,Android系統 提供了一個系統管理使用者連絡人資訊的內容提供者。通過它任何應用只要有許可權就可以查詢內容提供者的部分,然後讀或者寫特定的連絡人資訊。
Content provider還可以用來讀寫應用私人的資料。
Broadcast Receivers
Broadcast receivers可以對全部廣播進行回應的組件。許多廣播都是系統發送的,比如說當螢幕關閉時發送的廣播通知、電池 電量低時的廣播、或者拍照完畢的廣播。應用也可以建立廣播,比如說發個廣播讓其他程式知道有資料下載到裝置上,已經可以使用了。雖然廣播接受者沒有介面,但是當一個廣播事件發生時它可以在狀態列建立一個通知來通知使用者。通常廣播接受者只是一個做一個其他組件的入口,做的工作很少。比如說當收到某廣播時啟動一個Service來執行一些操作。
Android系統設計的一個獨特之處是任何應用都能啟動其他應用的組件。
比如說你想讓使用者使用裝置的網路攝影機拍個照,裝置上有專門的應用做了這個功能,你不需要寫一個相機應用,只需簡單的調用系統相機應用就可以拍照。當拍完後,會給你返回要使用 的照片的資料。對使用者來說,看起來就像相機是你應用的一部分。
當系統啟動一個組件時,會為這個應用單獨啟動一個進程(如果這個應用還沒啟動),然後執行個體化一些要用到的類。比如說,你的應用啟動了拍照應用的activity,那個activity運行在相機應用所在的進程,而不是你的應用的進程。因此,不像其他平台系統的應用,Android應用不僅有一個入口(沒有Java裡的main方法)。
由於系統把每個應用運行在不同進程,同時限制訪問其他應用檔案的許可權,你的應用不能直接啟用其他應用的組件。然而你可以直接調用Android系統的組件。想要啟用其他應用的組件,你必須在你的intent裡標明資訊告訴系統要啟動一個特定的組件。系統就會為你啟用那個組件。
啟用組件
四大組件裡的三種:activities、services、broadcast receivers都可以通過非同步呼叫intent來啟用。Intent在運行時(可以理解為當請求調用其他組件時)綁定調用和被調用的組件,無論組件是不是屬於你的應用。
通過Intent對象來建立一個intent,這個intent可以決定啟用一個特定的組件還是啟用一類組件。Intent可以是分為2中,顯式和隱式。
對activities和services來說,一個intent決定了要調用的行為(比如要顯示或者發送一些東西),也可能標明要使用資料(被調用的組件可能需要輸入一些資料)的URI。比如說,一個intent可能發出一個請求讓一個activity顯示某張照片或者開啟一個網頁。有些時候你啟動一個activity後可能還需要接收返回結果,在這種時候,activity會在一個Intent裡返回結果(比如說你可以發起一個intent讓使用者選擇一個連絡人,然後給你返回資訊,返回的intent裡可能就包括了指向被選連絡人的URI)。
對broadcast receivers來說,intent只需簡單的定義要接收廣播的通告就可以(比如想要接收裝置電量低的廣播只需在intent裡表明一個指示“電量低”的action)。
另外的組件 – content provider,不能被intent啟用。它是被針對Content Resolver發出的請求所啟用。這個content resolver處理content provider的所有直接事務,因此組件不需要調用provider而是直接調用content resolver的方法就可以了。這樣就在content provider和組件請求間保留了一個中介層,比較安全。
下面是幾種啟用不同類型組件的不同方法:
- 當你要開啟一個activity或者給一個已經開啟activity傳遞新資料時,通過給startActivity()或者startActivityForResult()(當你想要接收返回結果時)方法傳遞一個Intent就可以了。
- 當你要開啟一個service或者給一個正在啟動並執行service新指令時,通過給starService()方法傳遞一個Intent或者給bindService()傳入一個Intent來和service綁定就可以了。
- 你可以通過給sendBroadcast(),sendOrderedBroadcast(),sendStickyBroadcast()方法傳入一個Intent來執行個體化一個broadcast。
- 通過調用ContentResolver的query()方法來執行對content provider的查詢操作。
The Manifest 檔案
想要讓Android系統能啟動一個應用組件,系統需要通過查看應用的AndroidManifest.xml檔案來知道該組件的是否存在。你的應用必須在應用代碼根目錄下的這個檔案裡聲明所有的組件。
The manifest 除了聲明應用組件外還做了很多事,比如:
- 識別應用要使用的使用者權限,比如說訪問網路或者訪問使用者的連絡人;
- 聲明應用要求的使用者最低手機版本;
- 聲明應用要求的硬體、軟體特性,比如網路攝影機、藍芽或者多點觸屏;
- 聲明應用要使用的API庫(不是Android架構介面),比如說Google地圖介面。
你使用的activities,services,和content providers如果沒有在manifest裡聲明,對系統來說是找不到的,因此就無法運行。然而broadcast receivers有兩種選擇,要麼在manifest裡聲明,要麼也可以在代碼裡動態建立(建立一個BroadcastReceiver對象,然後調用registerReceiver()註冊)。
聲明組件能力的 intent filter
正如上面所說,你可以使用一個Intent來啟動activities,services,broadcast receivers。你可以在intent中顯式地使用組件的class名來指定要調用的組件。然而intent真正厲害的地方是隱式調用的概念。一個隱式的intent簡單的描述了要執行行為的類型(你也可以給想調用的行為傳遞資料),允許系統找到能夠執行你要求的行為的組件然後開啟它。如果有多個組件可以執行intent裡描述的行為,使用者需要選擇使用哪個。
系統是如何找到你的intent調用的組件的呢?答案是通過比較裝置上其他應用的manifest檔案裡組件的intent filters標籤。
當你在應用的manifest裡聲明一個activity時,你還可以給這個activity裡添加一個聲明activity能力的intent filter標籤,然後這個activity就可以給其他應用做出回應了。你可以通過給組件的標籤下添加一個標籤來為你的組件添加一個intent filter。
比如說如果你建立一個郵件應用,需要有一個activity來建立一個新郵件,你可以在該activity裡聲明一個intent filter,來對發送(新郵件)的intent做出回應,比如這樣:
<manifest ... > ... <application ... > <activity android:name="com.example.project.ComposeEmailActivity"> <intent-filter> <action android:name="android.intent.action.SEND" /> <data android:type="*/*" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </activity> </application></manifest>
如果有其他應用建立一個帶有ACTION_SEND的action的intent,然後通過startActivity()啟動,系統就可能啟動你的activity,然後使用者就可以編輯、發送一篇電子郵件。
聲明應用配置要求
市面上搭載Android系統的裝置種類太多了,這些裝置擁有的硬體設定都不一樣。為了避免你的應用被安裝到不具備你要求配置的手機上,你需要在manifest檔案裡標明你的應用要求的硬體、軟體配置。通常這些生命只是用來提示,手機系統不會瀏覽,但是第三方服務商比如Google應用市場會瀏覽他們,然後在使用者下載應用時協助使用者過濾那些有額外配置要求的應用。
比如說,如果你的應用要求使用網路攝影機,並且要求裝置最低配置為Android2.7(API Level7),你需要在manifest裡這樣標明:
<manifest ... > <uses-feature android:name="android.hardware.camera.any" android:required="true" /> <uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19" /> ...</manifest>
聲明了以後那些沒有網路攝影機或者Android版本低於2.1的裝置在Google應用市場上就不可以安裝你的應用了。
你也可以在你的應用中聲明要使用網路攝影機但是不是必須要求。這種情況下你的應用必須把上述標籤裡的required屬性設定為false,然後在運行過程中檢查裝置是否支援網路攝影機,如果沒有的話就禁止網路攝影機相關操作。
應用資源介紹
一個Android應用不僅僅是由程式碼群組成,它還有很多代碼以外的資源檔,比如說圖片、音頻檔案,或者其他跟應用顯示有關的東西。比如說你需要定義動畫、菜單、樣式、顏色還有互動介面的布局檔案等等。使用應用資源檔使得你更新一些東西更簡單,不用修改代碼,直接替換對應的資源檔。這樣你的應用就能儘可能多的適應不同的裝置環境(比如不同語言或者不同螢幕大小等)。
對於你項目中的每個資源,軟體開發工具都會給它定義一個唯一的整型ID,通過這個ID你可以從代碼中或者其他資源檔中引用對應的資源。比如說,你的應用中包含一個名為logo.png的圖片檔案(儲存在res/drawable/目錄下),SDK會產生一個名為R.drawable.logo的ID,你通過這個ID就可以引用logo圖片,插入到介面裡。
提供和原始碼分離的資源檔最重要的好處之一就是你可以為適配不同裝置提供不同的資源檔。比如說在XML中定義介面中的字元,你可以為這些字元準備不同語言版本,儲存在不同的檔案中。然後系統會根據使用者裝置設定中的語言,在檔案所在檔案夾的尾碼名字來找合適的字元來顯示(比如儲存在res/values-fr/下的法語字元,當使用者系統語言為法語時會顯示這個檔案夾下儲存的字元)。
Android支援許多不同的資源選擇方式。這個選擇方式主要取決於你為了在不同配置下使用不同資源時、建立的資源檔夾名稱中的字元尾碼。再舉個栗子,你應該習慣根據裝置螢幕尺寸或者方向為activity建立不同的布局檔案。當裝置螢幕豎屏時,你的布局裡有一個按鈕,當螢幕轉成橫屏時,你希望這個按鈕轉到橫屏。為了實現隨著螢幕方向改變布局,你可以定義2個不同的布局,然後給每個布局放到適當的、可以被正確選擇的、不同的檔案夾裡。這樣系統就會根據螢幕方向自動載入合適的布局了。
【苦讀官方文檔】2.Android應用程式基底本原理概述