編輯:關於android開發
寫在前面的話:接觸Android的時間也不短了,聽了視頻、看了書、敲了代碼,寫了博客,做了demo。。。但是想做出一款優秀的APP(哪怕是封裝一個不錯的功能)還有很長的路要走。於是前些日子我打算更加深入地往底層、往源代碼方向研究Android——我就買了一本《Android群英傳》拜讀一下,在剛讀到前言的時候,我發現作者推薦了閱讀官方的Training和Guide,我才意識到,其實之前我接觸到的各個渠道的Android知識,都是來自官方文檔,與其更加深入地了解Android,不如把官方文檔的內容好好拜讀一下,它才是最好的教材。從今天起,我將努力把Android官方文檔翻譯一遍,當然不是全部內容,而是我認為重要的知識點,一些很基礎的內容就略過了。
本文將從官方文檔中最開始的內容《Introduction》說起。
如需訪問官方原文,請您點擊這個鏈接:《Introduction to Android》。
Android應用程序提供了多種訪問入口
一個Android應用程序由不同的獨立組件構成,並且可以獨立調用,比如一個Activity可以提供一屏UI顯示,一個Service可以用於在後台執行任務。
在一個組件中啟動另一個組件,可以使用intent,甚至可以使用intent啟動其他一般用程序,這使得一個應用程序可以有多個訪問的入口,並且可以讓其他應用程序的某個組件看起來好像自己應用的一部分。
一個應用程序可適配不同設備
Android提供了可適配的框架,一種資源可以適配不同的設備。比如一個layout布局會根據不同設備的屏幕自動匹配。開發者可以在應用運行時查看應用程序所需權限,開發者也可以在自己開發的應用中聲明所需權限,Google Play可以自動篩選支持應用所需權限的設備,從而減少不必要的適配問題。
Android應用程序主要由Java編寫,Android SDK工具將代碼、資源文件和數據內容打包成APK文件。APK文件包含了該應用程序的所有組件,該APK文件可以在支持Android的設備上安裝並使用。
一旦安裝成功,應用程序將受到沙箱機制的保護:
Android操作系統是一個多用戶的Linux操作系統,每個應用程序就代表一個用戶。
默認情況下,系統為每個APP分配一個用戶ID(該用戶ID對於APP來說不可見,僅系統可見),系統使用一個APP來管理所有文件的權限,這個APP也有用戶ID,使用這個ID才能訪問這些權限。
每個應用程序都有獨立的虛擬機,這使得每個應用可以互不干擾地運行。
默認情況下,每個APP都有自己的Linux進程。一個應用的某個組件需要執行,Android就會啟動這個應用的進程;相反,當應用不再使用或系統內存緊張時,該應用所在進程將被停止。
通過上述要求,Android是一個滿足最小權限原則(principle of least privilege)的系統,也就是說,在默認情況下,每個APP只能啟動該它所需的功能組件,系統未給予其權限的內容,APP將無法訪問。
然而使用下列方式,應用程序之間可以共享數據,或者程序可以訪問系統服務:
下面將介紹APP的核心基本組件、manifest文件、與代碼分離的資源文件及如何使用資源文件修飾符適配不同的設備。
也就是所謂的四大組件,每個組件都有自己獨立的生命周期,管理者組件的創建和銷毀。
Activities
Activity代表了與用戶交互的UI(它並不是一個UI,而是一個用於呈現UI 的載體),您所看到的屏幕上的內容,都是以Activity作為載體的。如需訪問有關Activity的官方文檔,請您點擊這個鏈接:《Activities》,當然我也將在後續博文中翻譯該文檔。
Services
Service是一個運行在後台的組件,它主要用於長連接和遠程操作,它沒有與用戶交互的UI界面。比如說,Service可以與在後台運行音樂,或者從網上下載數據而不影響用戶的UI操作。可以在Activity中啟動或者綁定Service以便與其通信。
Content providers
content provider管理著一個APP中的數據信息。您可以將數據存儲在任何可以持久化保存的地方,如SQLite數據庫,文件系統,網絡上等。其他應用可以通過content provider訪問本應用的數據信息。例如,系統的聯系人應用程序中的Content Provider提供了通訊錄信息,使用ContactsContract.Data類(需配合Content Resolver)就可以訪問系統的通訊錄信息。
Content Provider對應用的數據隱私性做了較好的保護。
Broadcast receivers
Broadcast receivers用於接收系統發出的各式廣播信息。系統廣播有很多,如:點滅屏幕時,電量低時,獲取圖片時 等。應用程序也可以自定義廣播,如當APP下載了一些信息需通知其他APP“信息已下載完畢可供使用”時,應用可發出一條廣播,而其他應用可截獲該廣播。Broadcast receivers同樣無法進UI展示,但顯示一條Notification表示有廣播發出。更簡單地說,Broadcast receivers僅是發起了一個意圖,可以指導對該意圖感興趣的應用做一些事情。
Android系統的一個獨特設計就是任何一個APP都能其中另一APP的組件,例如,如果您打算使用系統攝像頭照一張照片,使用自己的應用就能啟動,而不必再從頭編寫照相功能的代碼,您也無需將自己APP的代碼與照相的應用程序的代碼有什麼關聯。您只需使用自己的activity啟動帶有照相功能的activity並返回照相的結果就行了。這個帶有照相功能的activity就好像是自己應用的一部分。
當您啟動了一個APP的組件,就啟動了該APP所在的進程,並初始化該組件的類,比如,您的APP啟動了相機應用中的activity,該activity將運行在屬於相機應用的進程中,而不是您的APP中。因此,Android應用並不存在唯一的入口(如沒有main()方法)。
通過intent這個異步請求,可以啟動activities, services, 和 broadcast receivers這三大組件,Intent在運行時將不同的組件做一綁定,不論這些組件是否來自同一應用。通過intent啟動組件有兩種方式:隱式intent和顯式intent,這兩種方式將在後續穩重中具體介紹。
對於啟動activity或service,intent可以附加一些action,或是一些指向具體數據內容的URI。例如某些intent打算啟動一個帶有展示圖片功能的activity,或是打算打開一個網頁,在某些情況下,啟動後的組件會通過intent返回一些數據(比如說您希望intent打開的是某個通訊錄的聯系人,並返回這個聯系人的信息,返回的信息就包含在intent中,而且還包含了指向這個聯系人的URI信息)。
對於broadcast receivers來說,可以在intent-filter中聲明想要接收什麼樣的廣播,比如說您打算在您的應用中收到系統發出的“電量低”的廣播,那麼只需要在您的broadcast receivers中配置有關“電量低”的消息就行了。
對於content provider來說,intent無法啟動。Content Provider需要和ContentResolver配對使用。 content resolver負責處理與之對象的ContentProvider事務,所以ContentProvider不用顯式地調用contentResolver中的方法,就能將數據傳遞出去。這種做法很好地將應用中的數據與訪問該數據的方法分離,提高了應用的安全性。
可以使用下列方法啟動相應組件:
啟動Activity: startActivity() 或 startActivityForResult() 啟動Service:startService();綁定Service:bindService() 啟動Broadcast:sendBroadcast(), sendOrderedBroadcast(), 或 sendStickyBroadcast() 如需查詢content provider中提供的數據信息,可調用ContentResolver.query()方法。在使用組件之前,需在Manifest文件中對組件進行注冊。除了注冊組件以外,Manifest文件還可以作如下事情:
為應用申請所需權限(如度取系統聯系人、訪問intent等),需配置 use-permissions 定義最小API ,需配置 minimum SDK Version 聲明使用應用所需的硬件和軟件配置(如藍牙、相機、支持多點觸控的屏幕),需use-features 應用所需鏈接的API庫,如 Google Maps library,需配置meta-data 其他配置activity的方法如下:
...
其中標簽的icon屬性用於配置啟動圖標。
標簽的name屬性用於注冊應用中的activity的子類,需使用全限定名注冊。
broadcast receivers除了可以在ManiFest文件中靜態注冊,還可以在代碼中使用registerReceiver()方法動態注冊。有關ManiFest文件的更多內容,請您點擊這個鏈接:《App Manifest》,我將在後續文章中翻譯該文檔。
intent的真正強大之處在於它的隱式啟動,隱式intent可以描述其想要啟動的目標組件所具備的特性而不具體指明目標組件的名字。
通過為組件配置 intent filters,組件具有被隱式intent篩選的能力,只有匹配了intent filters中的條件,該組件才能被隱式intent啟動。例如,您打算在應用中配置一個發送郵件的activity,使得通過隱式intent表明“發送郵件”的意圖,那麼您可以這樣為activity配置 intent filters:
...
更多有關intent filter的官方介紹,請您訪問這個鏈接:《Intents and Intent Filters》
支持Android的設備各不相同,它們支持的底層驅動也各有千秋,為了防止將需要某個底層驅動的應用(如帶有照相功能的應用)安裝在並不支持該功能的設備上(該設備沒有攝像頭),需在manifest文件中配置,這個配置信息在系統中僅是說明性質的(即Android系統並不讀取這個配置說明),但將應用發布到某個平台上(如Google play)時,該平台會讀取這些聲明。比如說, 您的應用需要調用系統攝像頭並運行在最小版本為Android 2.1(API 7)的設備上,您需要作如下配置:
...
低於android 2.1或不支持攝像頭的設備將無法在Google play上搜索到該應用。
您也可以聲明您的應用使用攝像頭但不是必須的,這需要將use-features標簽的android:required屬性設置為false,並在代碼中檢測設備是否有攝像頭、關閉所有與攝像頭有關的功能。
APP資源實現了與代碼的分離,這些資源包括圖片、影音等可視資源。例如,您可以定義animations,、menus、 styles、 colors或是activity的layout資源,使用資源配置,可以做到代碼的解耦,並使其與更多地設備適配。
對於每一個資源,SDK工具都會為之設置一個唯一的整型ID,通過這個ID,您可以在代碼中引用這個資源,
為各種不同的設備適配資源是APP資源的最大優勢,您可以在資源文件名中追加修飾符(qualifier)以匹配不同的設備。如res/values-fr/文件夾中放置法語的字符串信息,而默認的res/values/目錄下放置默認的字符串信息,系統會根據您安裝的設備系統語言自動匹配不同文件的內容。
類似這種限定符還有很多,比如您還可以為適配橫豎屏的不同布局而追加修飾符等。有關資源修飾符的官方文檔,請您點擊這個鏈接:《Providing Resources》。
android設備千千萬,這需要您的android應用程序具備很好的兼容性。為了更好的適配各式屏幕,android提供了修飾符。
關於兼容性,分為兩種:設備的兼容性(device compatibility)和APP的兼容性(app compatibility)。
對於設備的兼容性,您不必擔心,只要是能發布在Google play上的應用,都兼容android 設備。
但是對於APP的兼容性,您就得留意了,因為不同設備對硬件的支持不盡相同,比如有的應用需要指南針的底層支持,那麼不支持指南針的設備將無法運行該應用。
以下是檢測設備是否支持指南針功能,若不支持,應將其關閉:
PackageManager pm = getPackageManager();
if (!pm.hasSystemFeature(PackageManager.FEATURE_SENSOR_COMPASS)) {
// This device does not have a compass, turn off the compass feature
disableCompassFeature();
}
每一個android版本都為應用做了向後兼容的適配,也就是說,您應該為應用程序適配新的版本以做到向前兼容(以我的經驗來看,假設當前市面上占有率最高的版本是android 5.1,那麼您應將應用的targetSDKVersion設置為 23 (android 6.0),這個設置表明您的應用程序在android6.0 的設備上可以正常運行,這可以保證占有率最高的android 5.1的設備升級到android6.0時,您的應用程序不會崩潰。所以一般將targetSDKVersion設置為比目前市場占有率最高的版本設備高1-2個版本即可。)
在默認情況下,每個應用都沒有任何權限去訪問其他應用、系統設置和用戶的隱私數據。包括讀寫用戶的隱私信息(通訊錄和郵件),讀寫其他應用的數據,訪問Internet、使設備保持喚醒狀態等等。
基於android系統的沙箱機制,應用必須顯式地分享數據和資源,這需要顯式地申請權限:應用顯式地在配置中申請權限,還需獲得用戶的同意。
所有apk文件都必須用證書簽名,並由開發持有一個私有的key。這張簽了名的證書就是對該應用程序開發者的認證,這張證書無需由權威機構認證,而是由開發工具進行自我簽名,使用證書可以保護開發者的權益,並且系統可以允許或拒絕應用使用簽名級別的權限(signature-level permissions);證書還可以允許或拒絕應用請求與其他應用持有相同Linux ID(request to be given the same Linux identity)的權利。
安裝應用時,android賦予每個一包(android以包名區分不同應用)一個確定的Linux用戶ID(Linux User ID),從該應用的安裝到卸載,這個ID一直存在且保持不變。在不同的設備中,ID可能會不同;但這個ID在同一台設備上會保持唯一。
出於安全性的考慮,在一般情況下,兩個不同的包(應用)不能處於同一進程中;但是,您可以在AndroidManifest.xml文件的manifest標簽中的sharedUserId屬性中為不同的包(應用)配置相同的用戶ID(User ID),這時兩個包(應用)會被看作是一個應用,它們具有相同的用戶ID和文件權限(user ID and file permissions)。需特別注意的是,為了安全性的考慮,兩個應用具有相同的簽名,同時還配置了相同的sharedUserId屬性,這兩個應用才擁有相同的用戶ID。
一個應用存儲的數據都會被賦予該應用的用戶ID,其他應用無法共享這些數據。
在默認情況下,一個Android的應用程序為被賦予任何權限,這對用戶的體驗或數據的存取會產生不利影響。為了使用被設備保護的特性,您必須使用
標簽添加權限。
比如說,您希望模擬器可以接收發送過來的短消息時,可是使用下列代碼添加權限:
...
如果您申請的是基本權限(normal permission;基本權限意味著該權限不會對用戶的隱私或設備的運行造成太多負面影響),系統會自動賦予這些權限;如果您申請的是危險權限(dangerous permission;危險權限意味著該權限可能對用戶的隱私或設備的運行造成潛在的影響(potentially affect))【有關權限級別的官方介紹,請您點擊這個鏈接:《Normal and Dangerous Permissions》】,系統會顯式地告知並請求用戶授權。設備的版本不同,告知和請求的方式也不同:
若您的設備是 Android 6.0 (API level 23)或以上版本,並且應用設定的targetSdkVersion是 23 或以上時,應用會在運行階段向用戶請求權限,用戶也可以隨時撤銷賦予的權限,所以應用會在每次運行時查看自己的權限。更多有關運行時權限的介紹,你可以訪問我的博文:《Android 6.0及以上版本的運行時權限介紹》。 若您的設備是Android 5.1 (API level 22)或以下版本,並且應用設定的targetSdkVersion是 22 或以下時,應用會在安裝時請求用戶賦予權限。若您在新的APP版本中加入了新的權限,安裝新版本時,應用會請求用戶賦予該新增的權限。一旦您安裝了應用,就意味著您同意賦予所有請求的權限,若想取消任何權限,只能卸載該應用。有些時候,應用請求權限失敗時,會拋出SecurityException異常,但這個一場不什麼時候都會拋出,大多是情況下,請求權限失敗時只會打印Log。
一個特別的權限可能會在多處地方被使用:
調用系統內部的一些方法時:系統會阻止應用訪問系統內部的一些核心方法; 當啟動一個其它APP的Activity時; 當發送和接收一個廣播時,該權限可以決定誰可以接收該廣播,或者誰可以將該條廣播發動給您; 當操作content provider時; 當啟動或綁定服務時。為了保證您的應用總能適配新的API版本增加的權限,建議將targetSdkVersion設置得盡可能的高(as high as possible)。
系統為權限分成了若干個級別,其中最重要的兩個級別即為基本權限和危險權限。
基本權限說的是您的應用需要訪問沙箱以外的數據或資源,但是這對用戶隱私和系統的運行幾乎不會造成什麼影響。比如說“設置時區”權限就是一個基本權限。若您在manifest文件中配置了基本權限,那麼該權限會被自動賦予而無需請求用戶。 危險權限說的是應用會訪問用戶的隱私信息、對用戶存儲的數據造成潛在的影響或是影響了其他APP的運行等。比如說“讀取用戶的聯系人”就是危險權限,如果您在manifest文件中配置了危險權限,那麼該權限需要在使用時由用戶顯式賦予。所有的危險權限都被分成了權限組,若設備的版本號是 Android 6.0 (API level 23)或以上,並且targetSdkVersion為23或更高。當您的APP請求危險權限時,下列行為將會發生:
若您的應用正在申請manifest中配置的危險權限,系統會彈出一個對話框,該對話框描述了該危險權限所屬的權限組,而不僅僅是該權限。比如說,您的應用正在請求READ_CONTACTS權限時,系統僅僅會彈出該應用正在申請設備通訊錄(device’s contacts)的對話框。若用戶同意了該請求,系統僅會賦予請求的單個權限。 若您的應用正在申請manifest中配置的危險權限,並且用戶之前已經賦予了該權限所屬權限組的其他權限給應用,那麼此時這個危險權限將自動被賦予無需用戶同意。比如說,若應用之前已經獲得了READ_CONTACTS權限,那麼當應用請求WRITE _CONTACTS權限時,該權限將自動被賦予,而無需請求用戶。事實上,無論是基本權限還是危險權限都被分成了權限組,但是只有危險權限所在的權限組會發生上述的情形,所以您可以忽略權限組中的基本權限。
若設備的版本是Android 5.1 (API level 22)或以下,而且targetSdkVersion為22或以下,系統會在應用安裝時,聲明所需的所有權限,這些聲明是以權限組展示給用戶的而不是單個權限。
以下列出危險權限及其權限組:
若打算自定義權限,您需要在manifest文件中使用
標簽聲明。
比如說,若打算控制某個Activity的啟動權(誰可以啟動該Activity),您可以配置如下代碼:
...
其中
屬性是不能缺省的,該屬性表明了請求該權限的級別,或誰可以被允許持有該權限。
屬性是可選的,該屬性僅是用來以分組的形式將權限顯示給用戶,您可以將該屬性設置到一個標准權限組標准權限組(android.Manifest.permission_group)裡,也可以設置一個自定義的權限組。推薦使用前者,因為這樣可以減少彈出對話框的次數。
label 和 description都是用戶自定義的屬性,當用戶查看應用擁有的權限時,顯示的將是label屬性中的內容,而權限的具體介紹將是description中的內容。自定義的屬性名稱label應該簡潔明了,能准確地表示該權限保護的內容,而description應該用幾句話描述權限允許應用所做的事和可能帶來的對用戶隱私的窺探。下面是一個自定義的CALL_PHONE的label 和 description的例子:
directly call phone numbers
Allows the application to call
phone numbers without your intervention. Malicious applications may
cause unexpected calls on your phone bill. Note that this does not
allow the application to call emergency numbers.
若您在manifest文件中聲明了高級權限(High-level permissions),那麼這種權限不是所有組件都能獲取的,若希望針對某個組件獲取高級權限,您應當在該組件的標簽中用android:permission 屬性聲明該高級權限。
Activity權限:在activity標簽中聲明的高級權限可以控制 誰可以啟動該activity,您應當在調用Context.startActivity()和Activity.startActivityForResult()方法時判斷是否能啟動該activity。若未被賦予該權限,則這兩個方法將拋出SecurityException 異常; Service權限:在service標簽中聲明的高級權限可以控制 誰可以啟動或綁定該service,您需要在調用 Context.startService(), Context.stopService() 和 Context.bindService()方法時判斷是否可以啟動或綁定該service,若未被賦予該權限,則這三個方法將拋出SecurityException 異常; BroadcastReceiver權限:在receiver標簽中聲明的高級權限可以控制 誰可以發送廣播給該BroadcastReceiver,您應當在Context.sendBroadcast()方法返回以後再判斷權限是否被賦予,因為會嘗試將該broadcast發送給其他滿足條件的receiver,所以,如果聲明了高級權限的receiver沒有接受到broadcast,sendBroadcast()方法也不會拋出異常;若使用Context.registerReceiver() 方法動態注冊receiver,同樣可以賦予該receiver高級權限; ContentProvider權限:在provider標簽中聲明的高級權限可以控制 誰有權訪問該provider提供的數據(contentprovider還提供了URI Permission,將在稍後介紹)。與其他的組件稍有不同,provider中可以聲明兩種權限屬性: android:readPermission和android:writePermission,前者可以控制誰能讀取該provider的數據,後者可以控制誰能寫入該provider的數據。僅有寫入該provider權限的組件不代表您也能讀取,反之亦然。當您第一次檢索該provider時,該高級權限將被檢測(如果沒有權限,SecurityException將被拋出),其中ContentResolver.query()方法需要android:readPermission屬性, ContentResolver.insert(),ContentResolver.update(), ContentResolver.delete()這三者需要android:writePermission權限,若相應權限未設置,上述方法將拋出SecurityException異常。除了上述提到的為broadcast receiver聲明高級權限外,您還可以在調用Context.sendBroadcast()方式傳入一個在String類型的權限。
由於Broadcasts和receiver都可以被賦予權限,兩種權限都需要經過intent的篩選才能匹配。
處於安全的考慮,對於content provider,可以為其聲明保護自己的讀寫權限。比如說,獲取郵件需要權限,但賦予的URI卻指向了一個圖片浏覽器,該浏覽器無法打開郵件,因為浏覽器沒有被賦予打開郵件的權限。
為了解決這個問題,可以在啟動activity時為intent設置Intent.FLAG_GRANT_READ_ URI _PERMISSION 或 Intent.FLAG_GRANT_WRITE_URI_PERMISSION字段。
android textview 自動換行 整齊排版,androidtextview一、問題在哪裡? textview顯示長文字時會進行自動折行,如果遇到一些特殊情況,自
seeting菜單界面形成--優化,seeting菜單界面--本文是上一篇文章的優化版: 上文鏈接地址:http://www.cnblogs.com/zzw1994/p/
Android之自定義控件-下拉刷新,android控件實現效果: 圖片素材: &nbs
本節教程主要講解Android傳感器編程的基礎知識,包括加速度傳感器(acce