Pro Android學習筆記(十一):瞭解Intent(中)

Intent的構成html

Intent能夠帶有action,data(由URI表達),extra data(key/value map,鍵值對),指定的類名(成爲component name)。一個intent至少攜帶上述的一個內容。java

Action。Action名,在上一筆記中已經給出兩種例子,一種是系統自帶的,如Intent.ACTION_DAIL,一種是開發者經過AndroidManifest.xml進行註冊的,在建立intent時給出:Intent intent=new Intent(String action_name);。action_name字符串的名字前綴是類名。android

Data。由不一樣action決定有效的URI的格式。intent.setData(Uri.parse(」xxxxxx」));。被喚起的activity能夠同activity.getIntent()來得到intent,而後通該intent的getData()來獲取數據。app

//觸發方。  
Intent i = new Intent(actionName); 
String uriStr = "wei://www.flowingflying.com";
i.setData(Uri.parse(uriStr));
this.startActivity(i);ide


//被觸發方。須要在AndroidManifest.xml中在intent-filter中註冊data信息,後文詳細說明
Intent intent = this.getIntent(); 
String data = intent.getData();

通用的action即數據傳遞。Action和喚起的並不是是一對一的,例如Intent.ACTION_VIEW根據data,喚起不一樣的應用。這種一對多,也就是通用的action,在manifest中註冊時,須要聲明數據(URI)的要求。具體能夠參考:http://developer.android.com/guide/topics/manifest/data-element.html。ACTION_VIEW是經過schema進行區分。經過class名字、action名字等方式進行指定的稱爲explicit intent,能夠一對多的稱爲implicit intent。ui

<activity......> 
    <intent-filter>
  
         <action android:name="android.intent.action.VIEW" />
         <data android:scheme="http"/> 
         <data android:scheme="https"/>
 
    </intent-filter> 
</activity>
this

若是咱們本身的intent要傳遞data,也必需要在manifest中註冊data,不然intent會喚起失敗,報告ActivityNotFoundException的異常。google

比較經常使用的還有MIME type,例如註冊<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />表示要查看notes的集合(即目錄),而註冊<data android:mimeType="vnd.android.cursor.item/vnd.google.note" />則表示查看具體item,即查看具體的note。spa

擴展數據(Extra data)傳遞。uri的方式限制了信息的傳遞量。Extra的格式key/value對,key名字一般以包名開頭,而value能夠是任何基礎數據類型,或者是實現android.os.Parcelable的對象。.net

在IntentTestDemo.java(經過intent i喚起IntentBasicViewActivity)經過下面傳遞extra數據。
一、extra數據以bundle的方式在intent中存放,若是已經有bundle,將新的鍵值對加入其中,若是沒有bundle,則建立一個。將來確保key的惟一性
二、key名一般以包名開頭,本例以常量方式,實際爲:cn.flowingflying.android.pro.extra.string。
三、下面是最最簡單據類型,還能夠是array,例如putExtra(String name, int[] values); 
      能夠是Serializable對象,如putExtra(String name, Serializable value);以及Parcelable對象,如putExtra(String name,Parcelable value); 。
      能夠將bundle進行傳遞,如putExtra(String name, Bundle value);, 
      能夠將Intent進行傳遞,如putExtra(String name, Intent anotherIntent);
      能夠支持Array list:如putIntegerArrayListExtra(String name, ArrayList arrayList); putParcelableArrayListExtra(String name, ArrayList arrayList);和putStringArrayListExtra(String name, ArrayList arrayList)
     【注意】在intent中傳遞的不是reference(指針),而是copy一份,咱們修改對象,並不會影響已經copy進intent中bundle的數據,這點須要很是注意。

i.putExtra(IntentBasicViewActivity.EXTRA_FLOWINGFLYING_STRING, "Hello, Intent! ");

在IntentBasicViewActivity.java中經過如下代碼獲取extra數據。
Intent intent = this.getIntent(); 
Bundle b = intent.getExtras();  
String s =  b.getString(EXTRA_FLOWINGFLYING_STRING));

Android系統有已定義的key值,具體參見http://developer.android.com/reference/android/content/Intent.html#EXTRA_ALARM_COUNT

使用Component來喚起Activity

以前例子,咱們經過action name來喚起Activity。對於explicit intent,即明確指定調用哪一個activity,能夠經過給出該Component的的package name和class name來進行調用。下面咱們試驗採用四種相似的方式進行調用,這四種方式本質沒有區別。

private void basicTest1(){ 
    Intent intent = new Intent(); 
   //方式1:setComponent(ComponentName name);
    intent.setComponent(new ComponentName("cn.flowingflying.android.pro",
                                                                                 "cn.flowingflying.android.pro.IntentBasicViewActivity"));
    startActivity(intent); 
}

//要寫完整的class Name,不能寫IntentBasicViewActivity或者.IntentBasicViewActivity,不然報告找不到Activity的錯誤
private void basicTest2(){ 
    Intent intent = new Intent();  
    //方式2:setClassName(String packageName, String classNameInThatPackage); 
   intent.setClassName("cn.flowingflying.android.pro",    
                                       "cn.flowingflying.android.pro.IntentBasicViewActivity");

    startActivity(intent); 

//要寫完整的class Name,不能寫IntentBasicViewActivity或者.IntentBasicViewActivity,不然報告找不到Activity的錯誤
private void basicTest3(){ 
    Intent intent = new Intent(); 
   //方式3:setClassName(Context context, String classNameInThatContext);
    intent.setClassName(this,"cn.flowingflying.android.pro.IntentBasicViewActivity");
    startActivity(intent); 
}

private void basicTest4(){ 
    Intent intent = new Intent(); 
    //方式4:setClass(Context context, Class classObjectInThatContext);
   intent.setClass(this,IntentBasicViewActivity.class); 
    startActivity(intent); 

Intent的Category屬性

在AndroidManifest.xml中,咱們能夠設置intent的category,例如:

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

在應用啓動是,將尋找Activity標記爲CATEGORY_LAUNCHER來加載。Android定義了多個Category,具體能夠在http://developer.android.com/reference/android/content/Intent.html#CATEGORY_ALTERNATIVE中查閱。例如CATEGORY_HOME能夠做爲該應用的home screen,而CATEGORY_GADGET適合嵌入到某個activity中。

下面是兩個例子。例子1指明瞭action name,因爲存在多個匹配,系統將列出來,供用戶進行選擇,以下。

例子2在例子1的基礎上增長了intent.addCategory(Intent.CATEGORY_LAUNCHER);,增長對Category名字的匹配,能夠看到系統進行了進一步的過濾。:

咱們能夠經過PackageManager在代碼中,能夠不喚起intent就得到匹配的activity信息。以下

Intent intent = new Intent(Intent.ACTION_MAIN,null); 
intent.addCategory(Intent.CATEGORY_LAUNCHER); 
PackageManager pm = getPackageManager(); 
List<ResolveInfo> list = pm.queryIntentActivities(intent, 0);
 

for(ResolveInfo ri : list){  
    String packageName = ri.activityInfo.packageName
    String className = ri.activityInfo.name;  
    ... .... 
    //有了packageName和className,就能夠進行分析,而後經過Intent i= new Intent(packaname,className); startActivity(i);喚起咱們所需的acitivity。 

然而,經過PackageManager得到匹配的Activity的數量多於例子中系統提供給用戶選擇的activities的數量,爲什麼?特別是沒有將本應用顯示出來。經過category篩選屬於implicit intent的調用方式,不屬於指定軟件包名及類名的explicit intent的精確調用方式,對於implicit intent調用須要進行聲明,以下:

<activity  android:name="……"  android:label="@string/app_name" >
    <intent-filter> 
        <action android:name="android.intent.action.MAIN" /> 
        <category android:name="android.intent.category.LAUNCHER" /> 
        <category android:name="android.intent.category.DEFAULT"/> 
    </intent-filter> 
</activity>
 

activity的intent-filter中能夠有多個category描述,其中CATEGORY_DEFAULT表示可使用implicit intent調用,當咱們增長此項聲明後,本應用就出如今匹配的activity列表中。一樣,對於經過action name來調用的,不指定包名和類名的,也屬於implicit intent,一樣須要進行CATEGORY_DEFAULT的聲明,不然會出現ActivityNotFoundException的錯誤。若是activity沒有在intent fliter中設置爲CATEGORY_DEFAULT,咱們能夠用PackageManager獲取匹配的activities的信息,分析後獲得確切的包名和類名,經過explicit的方式喚起該activity。

此外Android說若是從launcher screen喚起時不須要DEFAULT,也就是此時acitivty只需MAIN和LAUNCHER,固然咱們也能夠DEFAULT設上。Android在DEFAULT上彷佛有些繁雜,簡單說若是咱們不但願App被其餘App經過implicit調用,咱們就不要設置DEFAULT。

在category中有一個有趣的類別:<category android:name="android.intent.category.HOME"/>,咱們在MainActivity以及另一個Activity增長該類別。

<application ...... > 
    <activity ...... > 
        <intent-filter> 
            <action android:name="android.intent.action.MAIN" /> 
            <category android:name="android.intent.category.HOME"/> 
            <category android:name="android.intent.category.LAUNCHER" />
            <category android:name="android.intent.category.DEFAULT"/> 
        </intent-filter> 
    </activity> 
    <activity android:name=".IntentBasicViewActivity" android:label="@string/intent_basic_test">
        <intent-filter> 
                <action android:name="android.intent.action.MAIN" /> 
            <category android:name="android.intent.category.HOME"/> 
            <category android:name="android.intent.category.DEFAULT"/> 
        </intent-filter> 
    </activity> 
    ...... 
</application>

左圖在代碼中經過PackageManager來查看匹配CATEGORY_HOME的信息;中圖經過StartActivity(intent)來喚起匹配CATEGORY_HOME的Activities時,系統給予用戶的選擇,若是在應用中按Home鍵,有一樣效果;右圖爲退出應用,按Home鍵,要求進入Home UI時,系統給予用戶的選擇。

相關連接: 個人Android開發相關文章

相關文章
相關標籤/搜索