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

來源:互聯網
上載者:User

Intent的構成

Intent可以帶有action,data(由URI表達),extra data(key/value map,索引值對),指定的類名(成為component name)。一個intent至少攜帶上述的一個內容。

Action。Action名,在上一筆記中已經給出兩種例子,一種是系統內建的,如Intent.ACTION_DAIL,一種是開發人員通過AndroidManifest.xml進行註冊的,在建立intent時給出:Intent intent=new Intent(String action_name);。action_name字串的名字首碼是類名。

Data。由不同action決定有效URI的格式。intent.setData(Uri.parse(”xxxxxx”));。被喚起的activity可以同activity.getIntent()來獲得intent,然後通該intent的getData()來擷取資料。

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

//被觸發方。需要在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。

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

    </intent-filter>
</activity>

如果我們自己的intent要傳遞data,也必須要在manifest中註冊data,否則intent會喚起失敗,報告ActivityNotFoundException的異常。

比較常用的還有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。

擴充資料(Extra data)傳遞。uri的方式限制了資訊的傳遞量。Extra的格式key/value對,key名字通常以包名開頭,而value可以是任何基礎資料類型,或者是實現android.os.Parcelable的對象。

在IntentTestDemo.java(通過intent i喚起IntentBasicViewActivity)通過下面傳遞extra資料。
1、extra資料以bundle的方式在intent中存放,如果已經有bundle,將新的索引值對加入其中,如果沒有bundle,則建立一個。未來確保key的唯一性
2、key名通常以包名開頭,本例以常量方式,實際為:cn.flowingflying.android.pro.extra.string。
3、下面是最最簡單據類型,還可以是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開發相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.