【苦讀官方文檔】2.Android應用程序基本原理概述
官方文檔原文地址
應用程序原理
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能夠在用戶使用別的應用的時候後臺播放音樂。或者也能夠在最好還是礙用戶交互的情況下,在後臺從server請求數據。其它組件,比方說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框架接口)。比方說谷歌地圖接口。
你使用的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文件中標明你的應用要求的硬件、軟件配置。通常這些生命僅僅是用來提示,手機系統不會瀏覽,可是第三方服務商比方谷歌應用市場會瀏覽他們。然後在用戶下載應用時幫助用戶過濾那些有額外配置要求的應用。
比方說。假設你的應用要求使用攝像頭。而且要求設備最低配置為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的設備在谷歌應用市場上就不能夠安裝你的應用了。
你也能夠在你的應用中聲明要使用攝像頭可是不是必須要求。
這樣的情況下你的應用必須把上述標簽裏的required屬性設置為false。然後在執行過程中檢查設備是否支持攝像頭,假設沒有的話就禁止攝像頭相關操作。
應用資源介紹
一個Android應用不僅僅是由代碼組成,它還有非常多代碼以外的資源文件,比方說圖片、音頻文件。或者其它跟應用顯示有關的東西。
比方說你須要定義動畫、菜單、樣式、顏色還有交互界面的布局文件等等。使用應用資源文件使得你更新一些東西更簡單,不用改動代碼,直接替換相應的資源文件。這樣你的應用就能盡可能多的適應不同的設備環境(比方不同語言或者不同屏幕大小等)。
對於你項目中的每一個資源。軟件開發工具都會給它定義一個唯一的整型ID,通過這個ID你能夠從代碼中或者其它資源文件中引用相應的資源。
比方說,你的應用中包括一個名為logo.png的圖片文件(保存在res/drawable/目錄下),SDK會生成一個名為R.drawable.logo的ID,你通過這個ID就能夠引用logo圖片。插入到界面裏。
提供和源碼分離的資源文件最重要的優點之中的一個就是你能夠為適配不同設備提供不同的資源文件。比方說在XML中定義界面中的字符,你能夠為這些字符準備不同語言版本號。存儲在不同的文件中。然後系統會依據用戶設備設置中的語言。在文件所在目錄的後綴名字來找合適的字符來顯示(比方存儲在res/values-fr/下的法語字符,當用戶系統語言為法語時會顯示這個目錄下存儲的字符)。
Android支持很多不同的資源選擇方式。這個選擇方式主要取決於你為了在不同配置下使用不同資源時、創建的資源目錄名稱中的字符後綴。再舉個栗子。你應該習慣依據設備屏幕尺寸或者方向為activity創建不同的布局文件。當設備屏幕豎屏時,你的布局裏有一個button,當屏幕轉成橫屏時,你希望這個button轉到橫屏。
為了實現隨著屏幕方向改變布局,你能夠定義2個不同的布局。然後給每一個布局放到適當的、能夠被正確選擇的、不同的目錄裏。這樣系統就會依據屏幕方向自己主動載入合適的布局了。
【趣讀官方文檔】1.管家的抉擇 (Android進程生命周期)
【苦讀官方文檔】2.Android應用程序基本原理概述