Android開發藝術探索筆記(一) Activity的生命週期和啓動模式(1)

Activity做爲Android開發中最經常使用的一個組件,是Android開發人員必須熟悉且掌握的重要內容。同時Activity也是在面試中常常被問到的一個方向。所以,掌握Activity的重要性也不言而喻。這或許也是爲何任大神會在《Android開發藝術探索》這本書中把Activity做爲第一章的用意吧。而在本章的博客中,除了對書中的內容作筆記以外,也會相應地增長一些內容,但願可以對Activity有一個較爲全面的介紹。若是在閱讀過程當中發現講述的內容中有什麼疏忽沒有記錄下來或者是錯誤的地方的話,歡迎在下方留言指出。下面開始進入正題吧:javascript

預備知識:任務棧/回退棧**

棧是一種常見的數據結構,具備先進後出,後進先出的特色。從數據形式上來講,它能夠用下面這一張圖來表示:
棧的圖像表達形式
在這個棧中,咱們每個新放進棧的數據,都會放在棧頭的位置,而其餘的在以前若是已經放進來的數據,則會被逐漸按順序往棧底下面移動,看起來就像是前面先被進來的數據被後面新放進來的數據往棧底下面壓同樣。這種狀況叫作壓棧。就好像一把手槍的彈夾,當咱們把裏面裝子彈的時候,後面放進去的子彈會被逐漸往底部擠壓下去。而當咱們須要取出數據時,由於棧就規定了一個進出口,就是棧頭(也叫棧頂),因此咱們取出數據的時候,也是要按照數據進來的順序,從棧頂開始取出,每取出一個順序,棧中的其餘數據就會忘上移,直到最後一個數據從棧頂被取出而結束。這種狀況叫作彈棧。而若是咱們不想要其餘的數據,值須要棧中倒數第二個數據的話,那也沒辦法,只能把這個數據前面的數據所有彈出棧,你才能取到這個數據。不然的話一切皆是免談。而在Android的設計中,是使用棧這種數據結構來存放Activity的,它有一個名字,叫作任務棧,也叫回退棧。關於棧的知識,到這裏已經基本能夠用來介紹Activity了,至於其餘方面的內容,可參考其餘博客或書籍。這裏推薦的是:程傑的《大話數據結構》一書。css

什麼是Activity:

Activity,中文「活動」。在任大神的書中,把它理解成界面。實際上我很是贊成這種說法,由於Activity實際上就是咱們在應用中展示出來的一個個用戶界面,它會加載指定的佈局文件來顯示各類UI元素,併爲這些元素設置事件處理函數,從而實現用戶與應用的交互。好比咱們打開一個手機App時,展示出來的登陸界面、註冊界面、主界面等,都是一個個不一樣的Activity。它是用戶能夠直接在App上用肉眼看獲得的界面操做,以及針對用戶對App的某些特定操做而進行的事件處理(這個是用戶不可見的)。html

Activity的組成:

在上面對Activity的介紹中,用以做爲用戶可見的部分顯示的是一份.xml格式的佈局文件,而用以佈置事件處理函數的則是一個Activity對象。那麼爲何咱們把肉眼可見的部分也叫做Activity呢?由於咱們能夠直接在Activity中對佈局文件進行操做,等於佈局文件是Activity對象的一個外延,但多數狀況下,咱們使用Activity的方式依舊爲Activity對象+xml佈局文件。不過,關於Activity的組成,卻並無那麼簡單。實際上,一個完整的Activity組成並無那麼簡單,在Activity與開發人員能夠設置的視圖,也就是對用戶界面進行佈局的範圍之上,還包括了其餘層次的封裝。如圖:java

activity組成
咱們能夠看到,在Activity之下有一個PhoneWindow,這個PhoneWindow其實是一個叫作Window的類的實現類。提及Window,相信有人試過在取消Activity自帶的標題欄的時候,調用了這麼一個方法:android

//取消系統自帶的標題欄
requestWindowFeature(Window.FEATURE_NO_TITLE);

而這個方法的具體模樣,是這樣的:web

public final boolean requestWindowFeature(int featureId) {
        return getWindow().requestFeature(featureId);
    }

咱們發現,它實際回調了一個getWindow().requestFeature(featureId)方法,而這個getWindow()返回的實際上就是一個Window類型的對象mWindow:面試

public Window getWindow() {
        return mWindow;
    }

那麼,當咱們查看這個Window源碼的時候,發現它實際上是抽象類編程

public abstract class Window {
    /** Flag for the "options panel" feature. This is enabled by default. */
    public static final int FEATURE_OPTIONS_PANEL = 0;
    /** Flag for the "no title" feature, turning off the title at the top * of the screen. */
    public static final int FEATURE_NO_TITLE = 1;
    /** Flag for the progress indicator feature */
    public static final int FEATURE_PROGRESS = 2;
    /** Flag for having an icon on the left side of the title bar */
    .....
}

咱們知道,抽象類要想發揮做用,那麼須要有一個子類去繼承抽象類,而PhoneWinsow這是這麼一個實現類。咱們所執行的去除標題欄的操做,實際上調用的也是這個PhoneWindow中的方法而已。這也從側面反映出咱們前面所說的,Activity的組成不只僅是一個Activity對象+xml佈局文件那麼簡單。儘管咱們常見的模式就是這樣,但實際上這已是通過封裝以後才展示出來的。ruby

Activity的建立、激活與銷燬

建立Activity

要在代碼中建立一個Activity,須要通過一下幾個步驟:
1.新建一個類,繼承自android.app.Activity.類的命名建議爲:xxxActivity樣式,好比LoginActivity
2.在AndroidManifest.xml文件中的 < application>節點下使用新的< activity>節點註冊該Activity,同時爲< activity>節點配置android:name屬性.取值爲Activity類的包名和類名,推薦爲每個< activity>節點配置android:label屬性。例如:網絡

<activity  android:name=".LoginActivity" android:label="@string/title_activity_login" >
  </activity>

注意:若是存在多個Activity,那麼各< activity>節點不區分前後順序。若是要調整第一個進入軟件顯示界面的Activity,那麼則需在該< activity>節點中配置如下信息:

<intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>

3.若是須要在Activity中加入xml佈局文件,則須要在res\layout目錄下建立並設計佈局,命名建議爲activity_xxx(與xxxActivity匹配),如activity_login。
4.設計完佈局文件以後,在Activity類中重寫onCreate()方法,並在該方法中經過調用setContentView()方法加載佈局。好比:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_registe
    }

以上爲手動建立Activity的方式,固然咱們也可使用IDE幫助實現。以Eclipse爲例:
1.快捷鍵:ztrl+N。彈出窗口以下:
這裏寫圖片描述
選擇Android目錄下-> Android Activity ,點擊Next,效果以下:
這裏寫圖片描述

選擇樣式,這裏選擇默認樣式Black Activity。點擊next,效果以下:
這裏寫圖片描述
在這裏,更改Activity Name欄目,下面Layout欄目也會發生自動變化,點擊finish。建立成功。

激活Activity

咱們建立了Activity以後,除非把它設置爲默認界面,不然都須要被激活纔可以使用。調用Activity類定義的startActivity(Intent)方法,便可激活新的Activity,其中:參數Intent對象能夠直接經過Intent類的構造方法來建立
在使用Intent類的構造方法時,指定2個參數,第1個參數是Context對象
第2個參數是被激活的Activity類,例如SecondActivity.class。例子以下:

//跳轉到另外一個Activity
startActivity(new Intent(this,SecondActivity.class));

如此,便實現了激活SecondActivity並跳轉至SecondActivity界面的操做

上面是激活Activity的第一種方法,而若是你須要在激活第二個Activity後對其設置,而且在該Activity執行finish以後返回數據給第一個Activity的時候,能夠用startActivityForResult()方法。用法以下:

Intent mIntent =new Intent(this,SecondActivity.class);
int requestCode = 0;
startActivityForResult(mIntent,requestCode)

同時,在第一個Activity重寫數據返回的處理辦法onActivityResult();用法以下:

protected void onActivityResult(int requestCode, int resultCode, Intent data) {  

}

注意:requestCode能夠隨便設置,但必須大於或等於0

銷燬Activity

調用Activity類定義的finish()方法便可銷燬當前Activity。

Activity的生命週期分析:

典型狀況下的生命週期分析

在正常狀況下。Activity會經歷如下生命週期,每一個生命週期都執行着一個聲明週期方法:

1.onCreate():在咱們前面的手動建立Activity的例子中便已經接觸到這個方法,它是Activity生命週期執行的第一個生命週期方法,表示的是Activity正在被建立,在這個生命週期方法裏咱們能夠執行一些初始化的工做。好比加載xml佈局文件,初始化元素控件以及加載相應的數據或者設置監聽器等。

2.onStart():表示Activity正在啓動,而且逐漸從不可見到可見直到Activity展現到前臺

3.onRestart():表示Activity正在重啓。通常狀況下,噹噹前的Activity由不可見狀態從新恢復爲可見狀態的過程當中,就會調用這個方法。

4.onResume():在Activity完全展現在前臺(徹底可見)的時候被調用,在執行完這個方法後,Activity會請求ActivityManagerService(下稱AMS)對它管理的視圖進行渲染,此時的Activity位於棧頂且保持運行狀態

5.onPause():該方法在Activity由可見狀態逐漸變爲不可見的狀態的過程當中調用。通常在系統準備去啓動或者恢復另外一個Activity的時候調用。這時可作一些數據存儲、中止動畫或者釋放一些消耗的CPU資源等操做,但注意不要作耗時操做。不然會形成卡頓現象或者ActiviNotResponding異常(ANR)。

6.onStop():表示Activity處於中止,即徹底不可見狀態。

7.onDestory():在Activity被完全銷燬以前調用,表示着Activity被完全移出了任務棧。是Activity的最後一個聲明週期方法。

關於Activity的生命週期,網上找了一張很是明瞭的示意圖:
這裏寫圖片描述

在這裏做兩點補充關於從onPause()–>onStop()的特例:
1.如書中所言,當新的Activity採用的是透明主題是,Activity不回調onStop()方法
2.當新啓動的Activity是一個對話框式的Activity,那麼onStop()方法一樣不會被回調。

關於書中提出的兩個問題,結合大神的解釋和本身的一些想法,概括以下:

問題1:onStart和onResume、onPause和onStop從描述上差很少,對咱們來講有什麼區別呢?

大神的解釋:onStart和onStop是從Activity是否可見的角度進行回調的。而onResume和onPause是否位於前臺這個角度來回調的。在實際開發中沒有其餘明顯區別。
個人想法:onStart和onPause對應的是一種動態的變化,前者是從不可見到逐漸可見再到徹底可見(onResume)的變化。然後者則是從徹底可見到逐漸不可見再到徹底不可見的狀態(onStop)。相應的,onResume和onStop對應的就是一個靜態改變。一旦徹底可見,馬上調用onResume,一旦不可見,馬上調用onStop。這也是爲何當新建的 Activity爲透明主題時,onStop方法不會被回調。由於從前臺,也就是顯示界面的窗口來看,Activity並無從窗口中消除,依舊爲可見狀態,只是這個Activity不能控制而已。

問題2:假設當前Activity爲A,若是這時用戶打開一個新的ActivityB,那麼B的onResume和A的onPause哪一個先執行呢?

大神的解釋:從源碼分析角度來看,當咱們要啓動一個Activity時,啓動Activity的請求會由Instrumentation來處理,而後它經過Bilder像AMS發送一個請求,而AMS內部維護着一個ActivityStack(任務棧),負責的是棧內的Activity的狀態同步,AMS經過ActivityThread去同步Activity的狀態從而完成生命週期的調用。在ActivityStack的源碼中,肯定了新的Activity啓動以前,棧頂的Activity要先onPause後,在ActivityStackSupervisor中的realStartActivityLocked方法調用scheduleLauchActivity方法來完成新Activity的onCreate、onStart、onResume的調用過程。
個人想法:從生命週期的做用描述來看,當咱們要啓動一個ActivityB而且在它由不可見到逐漸可見再到徹底可見的過程當中,無可避免的是會佔用前臺顯示的空間,也就是說在這個過程當中,會使得ActivityA失去徹底可見的狀態,變成局部可見或者逐漸不可見的狀態,而在這時候,就已經調用了A的onPause方法,而當B的onResume方法被調用時,若是B不是透明主題或者對話框式的Activity的話,這個時候A的onStop也會開始被調用。即:先調用A的onPause,再調用B的onResume.

ps:自主想法,未經推敲,若是有發現不妥的地方,可在下方評論指出,以便及時更改。

異常狀況下的生命週期分析

關於異常狀況下的生命週期分析,大神主要講了兩種狀況:

1.資源相關的系統配置發生改變致使Activity被殺死並從新建立

在發生由於系統配置忽然發生改變,須要當即殺死當前的Activity而且從新建立,就如手機忽然旋轉屏幕,須要從新加載適應屏幕變化的Activity的時候。Activity的生命週期如圖所示:
圖片來源網絡
在Activity被異常關閉而且須要從新恢復的時候,Activity會先被完全銷燬,其onPause、onStop、onDestroy方法都會被調用。以後纔再從新開始調用onCreate方法。但由於是異常關閉,在恢復Activity時咱們也不但願看到數據丟失的狀況。因而在Activity的onStop方法被調用前,會執行onSaveInstanceState方法保存Activity內的數據,在新恢復的Activity調用onRestoreInstanceState方法,而且把Activity銷燬前調用onSaveInstanceState方法所保存的Bundle對象做爲參數同時傳遞給onCreate和onRestoreInstanceState方法,經過二者的信息對比來判斷是否重建,若是肯定是重建了,則取出以前保存的數據而且恢復,這個過程出如今onStart以前。
而關於數據恢復的過程,工做流程以下:
1.Activity調用onSaveInstanceState保存數據
2.Activity委託Window去幫忙保存數據,就好像本身死前把信物交給信得過的人通常
3.Window在委託它的上層頂級容器取保存數據,這個容器是一個ViewGroup,在Activity中可能就是DecorView
4.頂層容器通知它的子元素來保存相關數據。
5.完成

注:當Activity正常銷燬時,系統不會調用onSaveInstanceState方法來保存數據,只有在Activity異常終止的而且有機會從新顯示的狀況下才會調用onSaveInstanceState方法。

2.資源內存不足致使低優先級的Activity被殺死

這種狀況下,數據存儲和恢復過程和狀況1是同樣的。可是這裏作個區分,在手機內存不足的時候,有時候咱們把應用退出到後臺,過了一會再打開的時候,發現它是從新啓動了應用,而不是像狀況2說的會恢復。由於在這裏涉及到的並非狀況2,事實上,狀況2針對的是Activity,是指應用在執行過程當中處於後臺的Activity被kill(殺死)。而上面所說的則是手機在整個應用處於後臺的時候,直接把整個應用銷燬掉,這屬於典型的生命週期調度過程(參見示意圖左側)。

下面記錄Activity的優先級狀況,也就是當內存不足時,系統會根據Activity的優先級從低到高kill掉一些不須要的Activity以釋放資源工其餘Activity調用。
1.前臺Activity,正在和用戶的交互的Activity,通常爲用戶對可控UI元素具備操做的能力。好比,點擊按鈕有反應。優先級最高。
2.可見但非前臺Actiyity,好比Activity彈出了一個對話框,致使Activity能夠可見,可是對控件不具備操做的能力,只能在對話框中進行交互,優先級次之
3.後臺Activity,位於後臺的不可見Activity,優先級最低,系統首先清理該部分的Activity。

對於狀況1的一個拓展:若是想讓系統配置發生改變後不從新建立,咱們能夠經過在 < activity>節點中設置 如下的屬性來實現:

android:configChanges="orientation"

在這裏,android:configChanges的做用是捕獲設備的變化,並回調相應的處理方法而不會從新恢復Activity。固然,關於ConfigChanges的屬性值是有不少的,但咱們須要定義多個屬性的時候,能夠用 | 號分割,好比:

android:configChanges="orientation|keyboardHidden"

而關於configChages的屬性值及其含義,能夠參考以下:
這裏寫圖片描述

Activity的啓動模式:

關於Activity的啓動模式,就要回顧咱們的預備知識——任務棧了。在Android中,系統是利用任務棧來存儲每次建立的Activity,這就意味着只要有屢次重複調用同一個Activity的現象,那麼咱們就要建立多個Activity而且把他們存儲到Activity中,這樣不只浪費存儲空間,還使得Activity的回退機制變得過於死板,不符合Android靈活開發的需求。因而,Android對任務棧就好了必定的功能封裝,造成了四種啓動模式:

1.standard(標準模式):這是系統默認的啓動模式,每建立一個新的Activity,都會產生一個新的Activity實例而且放入相應的任務棧中。和典型的棧調用數據相似沒多大區別。

2.singleTop(棧頂複用模式,也叫棧頂惟一模式):在這種模式下,若是要新建的Activity自己已經有一個Activity實例位於棧頂時,那麼這個Activity不會被從新建立,而是會回調onNewIntent方法取出當前請求的信息,而這個新建的Activity不會被系統調用onCreate、onStart方法。注意的是,該模式只使用於新Activity已經位於棧頂。不然的話仍是會建立新的Activity而且進行壓棧操做。

3.singTask(棧內複用模式,也叫任務惟一模式):在這個模式下,只要Activity在任務棧中存在,那麼當咱們新建該Activity時,會將棧內存在的Activity作置頂操做。也就是說,除非要建立的Activity已經位於棧頂,不然系統會在棧內將位於該Activity之上的全部Activity作彈棧操做,直到該Activity位於棧頂。而若是要建立的Activity在棧內不存在時,會直接建立並壓棧。

4.singleInstance(單實例模式):這是一種增強的singleTask模式,它除了具備singTask的一切特性以外,還增強了一點,就是具備此模式的Activity只能單獨的位於一個任務棧中。也就是說,若是ActivityA是singleInstance模式,在它啓動的時候,系統會爲它分配一個新的任務棧。因爲singleTask的複用性,在其餘須要建立Activity的時候,都不會建立新的Activity。而注意的是,由於singleInsyance模式所建立的實例是位於一個獨立的任務棧裏,因此當咱們銷燬Activity的時候,會先把棧頂Activity所在的任務棧裏面的Activity清理完畢再來清理該Activity。例如,Activity的啓動順序以下:
A(棧頂)
B(singleInstance)
C
D(棧底)
那麼當咱們連續按back鍵時,銷燬順序爲 A -> C -> D -> B

askAffinity與Activity的關係

在講述二者關係的時候,首先能夠聲明一下:在Android系統中,並非只有一個任務棧,不少時候,在每個應有程序之間都會存有一個任務棧,在這個應用中所建立出來的Activity,在通常狀況下會放入同應用下的任務棧中,而這個任務棧的名字爲應用的包名。那麼,有沒有特殊狀況,咱們建立的Activity會進入到其餘的任務棧之中呢?若是能夠,它又會跳轉到哪一個任務棧中呢?咱們能夠經過TaskAffinity屬性給出答案。
每個Activity都會有一個TaskAffinity參數,這個參數標識了Activity所須要進入的任務棧的名字。若是咱們不對其進行設置,那麼它默認爲當前應用的包名,也就是當前應用下的任務棧。而若是咱們對其設置了其餘應用的包名的話,那麼在一些特定狀況下,該Activity則會出現轉移的狀況,書中介紹了兩種狀況:

1.當TaskAffinity和singleTask啓動模式配對使用的時候

若是應用要加載singleTask模式的Activity時,首先該Activity會檢查是否存在與它的taskAffinity相同的任務棧。若是存在,那麼檢查棧內是否有已經實例化的Activity,若是有,那麼銷燬在該Activity以上的Activity並調用onNewIntent。若是沒有,那麼該Activity實例化併入棧。而若是任務棧不存在,那麼將從新建立出一個任務棧,併入棧。

2.當TaskAffinity與allowTaskReparenting結合的時候

在這種狀況下,若是該Activity的allowTaskReparenting設置爲true的時候,這個Activity會直接進入後臺,直到當和TaskAffinity名字相同的任務棧進入前臺的時候,此時的Activity會轉移到該任務棧中並處於棧頂位置。
書中例子:先有應用A、B。當在A中啓動B的一個ActivityC,而後按Home鍵回到桌面,打開B應用。此時你會發現顯示出來的是ActivityC。

給Activity制定啓動模式的方法

1.經過AndroidMenifest.xml爲Activity指定啓動模式,在相應的節點中添加屬性:

android:launchMode="launchName"

這裏的launchName爲四種啓動模式任意一種,注意爲英文!

2.在Intent中設置標誌位來指定啓動模式。好比:

Intent intent =new Intent();
intent.setClass(MainActivity.this,SecondActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);

注:當兩種方法同時應用時,以第二種方法爲準。

Activity中Intent與IntentFilter的匹配規則:

在前面介紹Activity的激活方法時,咱們已經介紹瞭如何去用Intent去啓動一個Activity,但咱們所講的啓動Activity是有兩種辦法,前面說的是顯式啓動,意便是能夠清楚知道Activity下一個跳轉的Activity是什麼。(從Intent的參數對象就能夠看出)。而關於啓動Activity的另外一種辦法–隱式啓動,則更多的是一舉經過Intent與IntentFilter的匹配來實現的。下面就介紹一下Activity中Intent與IntentFilter的匹配規則。

1.IntentFilter如何設定

在AndroidManifest.xml文件中,找到< application>,在指定的< activity>標籤內添加,如例:

<activity  android:name=".RegisterActivity" android:label="@string/app_name" >
         <intent-filter>
          <action android:name="android.intent.action.MAIN" />

         <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>

 </activity>

2.Intent與IntentFilter的聯合工做

Intent與IntentFilter的聯合工做表現爲:開發者在須要啓動一個Activity時,經過Intent向傳遞每一個Activity的IntentFilter發送一則消息,若是有某個Activity的預約義信息和接收到的Activity相匹配,則表示下一個要啓動的Activity爲該Activity。由於咱們在開發者中並不能直接透過代碼看到下一個Activity是什麼,只是透過這種信息匹配的方法去完成的Activity啓動過程,就是隱式啓動。

3.IntentFilter的過濾信息:

IntentFilter的過濾信息主要包括三種:action、category、data,三種過濾信息都有相應的功能。若是一個Intent傳遞的信息同時匹配了IntentFilter設定的過濾信息,那麼才能成功啓動目標Activity,不然就算失敗。不過注意的是,一個Activity能夠設定多個IntentFilter,只要有其中一組IntentFilter徹底匹配,一樣能夠開啓該Activity。
下面分別介紹三種過濾信息的做用:

action的匹配規則

action的本質是一個字符串,其做用是描述Intent所觸發的動做的名稱,咱們知道,一我的能夠有多種稱呼,當其餘人要找這我的時,只須要叫他其中一個名字就能夠了。一樣,在IntentFilter中,咱們能夠定義多個action,只要有一個action和Intent傳遞的信息匹配,那麼就算配合成功。注意的是,系統自己預約義了一些action,表明可啓動的一些預約義的Activity,好比撥號界面等這些預約義的action集中放在android.intent.action下,調用的時候從裏面選取,好比:

android.intent.action.SEND

action在IntentFilter中的定義格式以下:

//actionName表示你須要加入的action信息
<action android:name="actionName"/>

action在Intent中的調用格式以下:

String action="actionName";
Intent intent =new Intent(action);

category匹配規則

category和action的本質是一致的,但表明的意義不一樣,category描述的是目標組件的類別信息,代表這個目標能夠幹些什麼,好比系統預約義中的:

CATEGORY_GADGET:表示目標Activity是能夠嵌入到其餘Activity中的

固然,咱們也能夠給它進行自定義的設置。
而關於category的匹配規則,大體以下:若是Intent中含有category,那麼無論你有幾個,都須要和目標Activity在IntentFilter中設定的category匹配。哪怕有一個是不匹配的,都將報下面這個異常:

android.content.ActivityNotFoundException:No Activity found to handle Intent {act=actionName  cat=[categoryName]}

category在IntentFilter中的定義格式以下:

<category android:name="android.intent.category.LAUNCHER" />

category在Intent中的添加category調用格式以下:

String category ="categoryName";
intent.addCategory(category);

data匹配規則

data的匹配規則和action類似,若是IntentFilter中定義了data,那麼Intent中必須也要定義可匹配的data,可是由於data的結構與action不同,因此會有一些變化的地方。

data的組成

data由兩部分組成:mimeTypeURI。其中,mimeType指的媒體類型,能夠表示圖片image/jpeg,文本text/html ,音頻audio/mpeg4-generic 和視頻video/*等。而URI表示統一資源標識符(Uniform Resource Identifier),用以制定所需資源的存儲路徑。其結構以下:

<scheme>://<host>:<port>:/[<path>|<pathPrefix>|<pathfrefix>]

結構說明以下:
scheme:URI的模式,好比http、file等
host:URI的主機名,即當前資源所在的主機的IP地址,能夠用域名錶示,如www.baidu.com
port:URI的端口號,好比80,指得到資源的窗口路徑。
path、pathPrefix、pathPattern:表示路徑信息

data在IntentFilter的定義格式:

<data 
      android:mimeType="mimeName"
      android:scheme="schemeName"
      android:host="hostName"
      android:port="portName"
      android:path="pathName"
      android:pathPrefix="pathPrefixName"
      android:pathPattern="pathPatternName"
/>

或者:

<data android:mimeType="mimeName"/>
<data android:scheme="schemeName"/>
......
<data android:pathPattern="pathPatternName"/>

data在Intent中的調用方法有:

intent.setdata(Uri data);
intent.setDataAndNormalize(Uri data);
intent.setDataAndType(Uri data, String type);
intent.setDataAndType(Uri data, String type);
intent.setDataAndTypeAndNormalize(Uri data, String type);

至此,關於《Android開發藝術探索》第一章的讀書筆記已經完成。其中參考的數目有: 何紅輝《Android開發進階:從小兵到專家》 郭霖《第一行代碼》 零點起飛學編程系列《零點起飛學Android開發》 在看書過程當中,發現關於一個知識點的內容,每本書都會有一些相同的地方,但也會側重於另外一些不同的點。剛好也證實了這麼一句話:一本書只有20%的內容是有用的額,同時也是隻展示了應該展示的那20%,剩下的80%,要麼本身積累,要麼多多看其餘技術數籍。加油吧,羅馬不是一天建成的,要看的書還有不少,要走的路也有好長。(完)