閱讀484 返回首頁    go 阿裏雲 go 技術社區[雲棲]


Activity的intent詳解~

來自EOE~

隱式啟動Activity的intent到底發給哪個activity,需要進行三個匹配,一個是action,一個是category,一個是data,可以是全部或部分匹配
同樣適用於Service和BroadcastReceiver,下麵是以Activity為例

MainActivity.java --主Activity
TestActivity.java --需要隱式啟動的Activity


(1) 根據Action和Category來進行匹配

        <activity android:name=".TestActivity"  android:label="TestActivity">

        <intent-filter >

         <action android:name="cc.android/myaction.leo"/>

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

        </intent-filter>

        </activity>

        

在MainActivity.java裏啟動它:

intent.setAction( "cc.android/myaction.leo");

//不加下麵這行也行,因為intent的這個屬性默認值即係Intent.CATEGORY_DEFAULT

intent.addCategory(Intent.CATEGORY_DEFAULT);

startActivity( intent );

總結:

a.在某個Activity裏用startActivity()方法發送一個intent,這個intent設定了一些條件,比如用方法setAction(),addCategory()設定了兩個屬性,

  發送了這個intent之後,android會去係統裏保存的MainManifest.xml清單(假設這個係統存放全部apk清單的文件為MainManifest.xml)裏查找符合這兩個屬性的activity,然後啟動它。

  查找過程是怎樣的呢?

  我猜測:在安裝某個apk的時候,android係統會把這個apk的清單文件裏內容複製一份至係統的某個清單文件裏(假如這個係統存放全部apk清單的文件為MainManifest.xml)

  當某個Activity用startActivity(intentOther)方法向係統發送了一個intent(假如為intentOther),那麼android係統會去查找這個MainManifest.xml裏注冊的<intent-filter >屬性,

  查找到符合這個 intentOther 的就啟動這個Activity,如果有多個這樣的Activity符合條件的話,就跳出一個對話框讓用戶選擇究竟要啟動哪一個

  

  上麵那個自定義的Action字符串("cc.android/myaction.leo",當然也可以寫成這樣"cc.android.myaction.leo",同時AndroidManifest.xml裏也要寫成這樣)是係統唯一的,

  所以係統很容易就能匹配到。

b.任何一個需要隱式啟動的Activity都必須要有這項:<category android:name="android.intent.category.DEFAULT"/>

例外情況是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中沒有必要加入android.intent.category.DEFAULT,當然加入也沒有問題

c.假如有兩個Activity,它們的在AndroidManifest.xml裏配置如下:

<activity android:name="MyActivityOne" android:label="@string/activityOne">

<intent-filter>

<action android:name="hello.leo.liao" />

<action android:name="hello.leo.leo" />

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

</intent-filter>

</activity>



<activity android:name=".MyActivityTwo" android:label="@string/activityTwo">

<intent-filter>

<action android:name="hello.leo.liao" />

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

</intent-filter>

</activity>



在MainActivity.java裏發送一個intent:

intent.setAction( "hello.leo.liao");

//不加下麵這行也行,因為intent的這個屬性默認值即係Intent.CATEGORY_DEFAULT

intent.addCategory(Intent.CATEGORY_DEFAULT);

startActivity( intent );



這樣的話,android係統會跳出一個對話框讓你選擇啟動哪一個Activity(MyActivityOne還是MyActivityTwo)

如果把上麵的intent.setAction( "hello.leo.liao");改為intent.setAction( "hello.leo.leo");的話,就自動匹配到MyActivityOne

就是說如果category和action都相同的話,會跳出一個對話框讓用戶選擇要啟動哪一個activity;

如果category相同,而action不相同,就可以匹配到相應的activity

d.單單靠添加addCategory屬性不能匹配,如:

Intent intent = new Intent();

intent.addCategory(Intent.CATEGORY_DEFAULT);

intent.addCategory("android.intent.category.hello");

startActivity(intent);


<activity android:name=".MyActivityTwo" android:label="@string/activityTwo">

<intent-filter>

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

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

</intent-filter>

</activity>

e.當匹配不上任何Activity的話,會發生異常,跳出對話框:很抱歉...某某應用程序意外停止,請重試。

f.Service和BroadcastReceiver 同理

(2) 根據Action和Data匹配

<activity android:name=".MyActivityTwo" android:label="@string/activityTwo">

<intent-filter>

             <action android:name="android.intent.action.leo"></action>

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

                <data android:scheme="x-id"></data>

</intent-filter>

</activity>



//Uri uri = Uri.parse("x-id://www.google.com/getDetails?id=123");//這個也可以

//Uri uri = Uri.parse("x-id");//這個不行

//Uri uri = Uri.parse("x-id://");這個可以

Uri uri = Uri.parse("x-id:");//這個可以

            Intent in = new Intent();

            in.setAction("android.intent.action.leo");//去掉這行不行,單靠data不能匹配

            in.addCategory(Intent.CATEGORY_DEFAULT);//可以去掉這行,因為intent的默認category值即係Intent.CATEGORY_DEFAULT

            in.setData(uri);//去掉這行不行

            startActivity(in);

            

總結:如果在AndroidManifest.xml裏麵指定了<data>這行,那麼,需要匹配到它的話,在代碼裏必須要設置intent的data,如上麵的in.setData(uri)    

Data的語法:

<data android:host="string"

      android:mimeType="string"

      android:path="string"

      android:pathPattern="string"

      android:pathPrefix="string"

      android:port="string"

      android:scheme="string" />

      

Uri的格式:scheme://host:port/path or pathPrefix or pathPattern



如果scheme沒有指定,那其它的屬性均無效;

如果host沒有指定,那麼port,path,pathPrefix,pathPattern均無效;

如果在manifest裏這樣寫:<data android:scheme="something" android:host="project.example.com" />

那麼Uri uri = Uri.parse("something://project.example.com"); 才可以匹配

再如:

<data android:scheme="something" android:host="project.example.com" android:port="80"/>

等同於這樣寫:

<data android:scheme="something"/>

<data android:host="project.example.com"/>

<data android:port="80"/>

那麼Uri uri = Uri.parse("something://project.example.com:80"); 才可以匹配

不知為何,下麵這個不行:

<data android:scheme="content" android:host="com.example.project" android:port="200" android:path="folder/subfolder/etc"/>

Uri uri = Uri.parse("content://com.example.project:200/folder/subfolder/etc")

下麵這樣也不行

<data android:scheme="content" android:host="com.example.project" android:port="200" android:path="folder"/>

Uri uri = Uri.parse("content://com.example.project:200/folder")

可以有多個data,隻需匹配其中一個即可

<activity android:name=".MyActivityTwo" android:label="@string/activityTwo">

<intent-filter>

             <action android:name="android.intent.action.leo"></action>

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

                <data android:scheme="x-id"/>

                <data android:scheme="something"/>

</intent-filter>

</activity>


           Intent in = new Intent();

            in.setAction("android.intent.action.leo");

            in.addCategory(Intent.CATEGORY_DEFAULT);

            in.setData(Uri.parse("something:"));//或者用這個亦可in.setData(Uri.parse("x-id:"));            

            startActivity(in);      
      
(3)  根據action和data的mimeType屬性匹配          

<activity android:name=".MyActivityTwo" android:label="@string/activityTwo">

<intent-filter>

<action android:name="android.intent.action.VIEW"></action>

<data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />

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

</intent-filter>

</activity>

在java代碼裏這樣寫就可以匹配到這個activity:

            Intent in = new Intent();

            in.setAction("android.intent.action.VIEW");

            in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因為Category默認值即係Intent.CATEGORY_DEFAULT

            in.setType("vnd.android.cursor.dir/vnd.google.note");

            startActivity(in); 


  單靠data的mimeType屬性不能匹配,就算這個mimeType是唯一的也不行(比如in.setType("leo.android.cursor.dir/vnd.google.leo");),需要有一個action配合   

  可以有多個mimeType,在java代碼裏隻需匹配其中一個即可:

  <activity android:name=".MyActivityTwo" android:label="@string/activityTwo">

<intent-filter>

  <intent-filter>

<action android:name="android.intent.action.VIEW"></action>

<data android:mimeType="leo.android.cursor.dir/vnd.google.leo" />

<data android:mimeType="leo.android.cursor.dir/vnd.google.liao" />

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

</intent-filter>

</activity>

這樣可以啟動MyActivityTwo這個Activity:

Intent in = new Intent();

            in.setAction("android.intent.action.VIEW");

            in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因為Category默認值即係Intent.CATEGORY_DEFAULT

            in.setType("leo.android.cursor.dir/vnd.google.liao");

            startActivity(in);

      或者這樣也可以啟動MyActivityTwo這個Activity:   

      Intent in = new Intent();

            in.setAction("android.intent.action.VIEW");

            in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因為Category默認值即係Intent.CATEGORY_DEFAULT

            in.setType("leo.android.cursor.dir/vnd.google.leo");

            startActivity(in);

     
  scheme和mimeType隻能有其中一個,下麵這樣通不過

  AndroidManifest.xml裏:

  <data android:scheme="something" android:host="project.example.com"

android:port="80"

android:mimeType="leo.android.cursor.dir/vnd.google.leo" />  




<data android:scheme="something" android:host="project.example.com"

android:port="80" />

<data android:mimeType="leo.android.cursor.dir/vnd.google.leo" />

java代碼裏:

匹配不上:

Intent in = new Intent();

            in.setAction("android.intent.action.VIEW");

            Uri uri = Uri.parse("something://project.example.com:80");

            in.setData(uri);

            in.setType("leo.android.cursor.dir/vnd.google.leo");

            startActivity(in);                  

            

            這樣還是匹配不上:

            Intent in = new Intent();

            in.setAction("android.intent.action.VIEW");

//            Uri uri = Uri.parse("something://project.example.com:80");

//            in.setData(uri);

            in.setType("leo.android.cursor.dir/vnd.google.leo");

            startActivity(in);
         

            這樣還是匹配不上:

            Intent in = new Intent();

            in.setAction("android.intent.action.VIEW");

            Uri uri = Uri.parse("something://project.example.com:80");

            in.setData(uri);

//            in.setType("leo.android.cursor.dir/vnd.google.leo");

            startActivity(in);

  
(4)   一個Activity裏可以有多對<intent-filter></intent-filter>  隻要匹配其中一對,即可啟動這個Activity

<activity android:name=".MyActivityTwo" android:label="@string/activityTwo">

<intent-filter>

<action android:name="android.intent.action.VIEW"></action>

<data android:scheme="something" android:host="project.example.com"

android:port="80" />

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

</intent-filter>


<intent-filter>

<action android:name="android.intent.action.VIEW"></action>

<data android:mimeType="leo.android.cursor.dir/vnd.google.leo" />

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

</intent-filter>


<intent-filter>

<action android:name="hello.hi.liao"></action>

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

</intent-filter>


</activity>


java代碼裏:

匹配第一對<intent-filter> 可以啟動MyActivityTwo這個Activity:

Intent in = new Intent();

            in.setAction("android.intent.action.VIEW");

            in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因為Category默認值即係Intent.CATEGORY_DEFAULT

            Uri uri = Uri.parse("something://project.example.com:80");

            in.setData(uri);

            startActivity(in);

   匹配第二對<intent-filter> 也可以啟動MyActivityTwo這個Activity:    

   Intent in = new Intent();

   in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因為Category默認值即係Intent.CATEGORY_DEFAULT

            in.setAction("android.intent.action.VIEW");

            in.setType("leo.android.cursor.dir/vnd.google.leo");

            startActivity(in);    

   
  匹配第三對<intent-filter> 也可以啟動MyActivityTwo這個Activity:      

  Intent in = new Intent();

            in.setAction("hello.hi.liao");

            in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因為Category默認值即係Intent.CATEGORY_DEFAULT

            startActivity(in);      

   
全部總結:

1.  <action/>包含在 <intent-filter></intent-filter> 標簽對裏,而且是必不可少的!不管以哪一種方式來匹配,都不可缺少這個<action/> ,可以有多個,至少要有一個。

如有多個的,話隻需要匹配其中一個即可找到這個activity

<action>裏的屬性值大多數是在Intent裏定義的,比如<action android:name="android.intent.action.VIEW"/>裏的屬性值就等於 Intent.ACTION_VIEW,

在這個Intent類裏以ACTION開頭定義的常量都是。當然,也可以自定義。  


2.  任何一個需要隱式啟動的Activity都必須要有這項:<category android:name="android.intent.category.DEFAULT"/>

例外情況是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中沒有必要加入android.intent.category.DEFAULT,當然加入也沒有問題  

<category>裏的屬性值大多數是在Intent裏定義的,比如  <category android:name="android.intent.category.DEFAULT"/>裏的屬性值就等於 Intent.CATEGORY_DEFAULT,

在這個Intent類裏以CATEGORY開頭定義的常量都是。當然,也可以自定義。  


3.一個Activity裏可以有多對<intent-filter></intent-filter>  隻要匹配其中一對,即可啟動這個Activity 


4.在<intent-filter></intent-filter>裏可以有多個<data android:mimeType="xxxx"/>,隻需匹配其中一個即可.注意:不可以同時出現第5點的標簽對,即下麵這條。

5.在<intent-filter></intent-filter>裏可以有多個<data android:scheme="xxxx" android:host="yyyy" android:port="uuu"/>,隻需匹配其中一個即可。

語法:

<data android:host="string"

      android:mimeType="string"

      android:path="string"

      android:pathPattern="string"

      android:pathPrefix="string"

      android:port="string"

      android:scheme="string" />

      可以分開寫,如:

      <data android:scheme="something" android:host="project.example.com" android:port="80"/>

等同於這樣寫:

<data android:scheme="something"/>

<data android:host="project.example.com"/>

<data android:port="80"/>


在java代碼裏,Uri的格式:scheme://host:port/path or pathPrefix or pathPattern

注意:不可以同時出現第4點的標簽對,即上麵那條。






6.在<intent-filter></intent-filter>裏可以有多個<action android:name="xxxx"> ,隻需匹配其中一個即可。







7.當匹配不上任何Activity的話,會發生異常,跳出對話框:很抱歉...某某應用程序意外停止,請重試。







8.上麵所說的全部適用於Service和BroadcastReceiver,隻需把<activity ...></activity>換成<service ...></service>或<receiver ...></receiver>即可。



9.剛參考了一下packages\apps\HTMLViewer\AndroidManifest.xml,第4和第5條應該是不衝突才對,但是實際測試中卻是衝突,暫時未到找原因。匹配方式請看:用於打開HTML文件的intent






在被啟動的Activity(本例為MyActivityTwo)裏接收數據:

Intent intent = getIntent();

String intentCategories = intent.getCategories()

String intentType = intent.getType();

Uri uri = intent.getData();

String uriScheme = uri.getScheme();

String uriPath = uri.getPath();

String uriHost = uri.getHost();

String uriEncodedPath = uri.getEncodedPath();

最後更新:2017-04-03 16:48:50

  上一篇:go 圖片onerror事件,為圖片加載指定默認圖片
  下一篇:go android發送鍵盤事件(應用層)