下面通過(guò)代碼分析每個(gè)部分的功能。
<intent-filter android:label="@string/Asen's blog">
<action android:name="android.intent.action.MAIN" />
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.EDIT" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.ALTERNATIVE" />
<data android:mimeType="video/mpeg" android:scheme="http".../>
<data android:mimeType="audio/mpeg" android:content="com.example.project:200/folder/subfolder/etc"/>
</intent-filter>
每個(gè)action, category, data都是一行,如果有多個(gè)就寫多行。"android.intent.action.MAIN" and "android.intent.category.LAUNCHER"這兩個(gè)是程序入口點(diǎn)的filter必須部分。比如說(shuō)短信這個(gè)應(yīng)用,當(dāng)你點(diǎn)擊MMS的圖標(biāo)程序啟動(dòng)后,映入使用者的一個(gè)界面(所有收到的短信列表),這個(gè)短信列表界面就是程序的入口點(diǎn),通俗的講就是一個(gè)application啟動(dòng)后顯示的第一個(gè)界面。另外,"android.intent.category.DEFAULT"這個(gè)category是用來(lái)指明組件是否可以接收到隱式Intents,所以說(shuō)除了程序入口點(diǎn)這個(gè)filter不用包含DEFAULT category外,其余所有intent filter都要有這個(gè)category。
data有兩部分構(gòu)成,一個(gè)是數(shù)據(jù)類型,另一個(gè)是URI。每個(gè)URI包括四個(gè)屬性參數(shù)(scheme,host, port, path),形如:scheme://host:port/path
舉個(gè)例子 content://com.examplproject:e.200/folder/subfolder/etc 這個(gè)列子中scheme是content,host是com.examplproject,port是200,path是folder/subfolder/etc
更多例子請(qǐng)參考:http://hi.baidu.com/wishwingliao/blog/item/0a38ccfce06f39e8fc037f85.html
隱式啟動(dòng)Activity的intent到底發(fā)給哪個(gè)activity,需要進(jìn)行三個(gè)匹配,一個(gè)是action,一個(gè)是category,一個(gè)是data,可以是全部或部分匹配
同樣適用于Service和BroadcastReceiver,下面是以Activity為例
MainActivity.java --主Activity
TestActivity.java --需要隱式啟動(dòng)的Activity
(1) 根據(jù)Action和Category來(lái)進(jìn)行匹配
<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里啟動(dòng)它:
intent.setAction( "cc.android/myaction.leo");
//不加下面這行也行,因?yàn)閕ntent的這個(gè)屬性默認(rèn)值即系Intent.CATEGORY_DEFAULT
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity( intent );
a.在某個(gè)Activity里用startActivity()方法發(fā)送一個(gè)intent,這個(gè)intent設(shè)定了一些條件,比如用方法setAction(),addCategory()設(shè)定了兩個(gè)屬性,
發(fā)送了這個(gè)intent之后,android會(huì)去系統(tǒng)里保存的MainManifest.xml清單(假設(shè)這個(gè)系統(tǒng)存放全部apk清單的文件為MainManifest.xml)里查找符合這兩個(gè)屬性的activity,然后啟動(dòng)它。
查找過(guò)程是怎樣的呢?
我猜測(cè):在安裝某個(gè)apk的時(shí)候,android系統(tǒng)會(huì)把這個(gè)apk的清單文件里內(nèi)容復(fù)制一份至系統(tǒng)的某個(gè)清單文件里(假如這個(gè)系統(tǒng)存放全部apk清單的文件為MainManifest.xml)
當(dāng)某個(gè)Activity用startActivity(intentOther)方法向系統(tǒng)發(fā)送了一個(gè)intent(假如為intentOther),那么android系統(tǒng)會(huì)去查找這個(gè)MainManifest.xml里注冊(cè)的<intent-filter >屬性,
查找到符合這個(gè) intentOther 的就啟動(dòng)這個(gè)Activity,如果有多個(gè)這樣的Activity符合條件的話,就跳出一個(gè)對(duì)話框讓用戶選擇究竟要啟動(dòng)哪一個(gè)
上面那個(gè)自定義的Action字符串("cc.android/myaction.leo",當(dāng)然也可以寫成這樣"cc.android.myaction.leo",同時(shí)AndroidManifest.xml里也要寫成這樣)是系統(tǒng)唯一的,
所以系統(tǒng)很容易就能匹配到。
b.任何一個(gè)需要隱式啟動(dòng)的Activity都必須要有這項(xiàng):<category android:name="android.intent.category.DEFAULT"/>
例外情況是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中沒(méi)有必要加入android.intent.category.DEFAULT,當(dāng)然加入也沒(méi)有問(wèn)題
c.假如有兩個(gè)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里發(fā)送一個(gè)intent:
intent.setAction( "hello.leo.liao");
//不加下面這行也行,因?yàn)閕ntent的這個(gè)屬性默認(rèn)值即系Intent.CATEGORY_DEFAULT
intent.addCategory(Intent.CATEGORY_DEFAULT);
startActivity( intent );
這樣的話,android系統(tǒng)會(huì)跳出一個(gè)對(duì)話框讓你選擇啟動(dòng)哪一個(gè)Activity(MyActivityOne還是MyActivityTwo)
如果把上面的intent.setAction( "hello.leo.liao");改為intent.setAction( "hello.leo.leo");的話,就自動(dòng)匹配到MyActivityOne
就是說(shuō)如果category和action都相同的話,會(huì)跳出一個(gè)對(duì)話框讓用戶選擇要啟動(dòng)哪一個(gè)activity;
如果category相同,而action不相同,就可以匹配到相應(yīng)的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.當(dāng)匹配不上任何Activity的話,會(huì)發(fā)生異常,跳出對(duì)話框:很抱歉...某某應(yīng)用程序意外停止,請(qǐng)重試。
f.Service和BroadcastReceiver 同理
(2) 根據(jù)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");//這個(gè)也可以
//Uri uri = Uri.parse("x-id");//這個(gè)不行
//Uri uri = Uri.parse("x-id://");這個(gè)可以
Uri uri = Uri.parse("x-id:");//這個(gè)可以
Intent in = new Intent();
in.setAction("android.intent.action.leo");//去掉這行不行,單靠data不能匹配
in.addCategory(Intent.CATEGORY_DEFAULT);//可以去掉這行,因?yàn)閕ntent的默認(rèn)category值即系Intent.CATEGORY_DEFAULT
in.setData(uri);//去掉這行不行
startActivity(in);
總結(jié):如果在AndroidManifest.xml里面指定了<data>這行,那么,需要匹配到它的話,在代碼里必須要設(shè)置intent的data,如上面的in.setData(uri)
Data的語(yǔ)法:
<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沒(méi)有指定,那其它的屬性均無(wú)效;
如果host沒(méi)有指定,那么port,path,pathPrefix,pathPattern均無(wú)效;
如果在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"); 才可以匹配
不知為何,下面這個(gè)不行:
<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")
可以有多個(gè)data,只需匹配其中一個(gè)即可
<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:"));//或者用這個(gè)亦可in.setData(Uri.parse("x-id:"));
startActivity(in);
(3) 根據(jù)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代碼里這樣寫就可以匹配到這個(gè)activity:
Intent in = new Intent();
in.setAction("android.intent.action.VIEW");
in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因?yàn)镃ategory默認(rèn)值即系Intent.CATEGORY_DEFAULT
in.setType("vnd.android.cursor.dir/vnd.google.note");
startActivity(in);
單靠data的mimeType屬性不能匹配,就算這個(gè)mimeType是唯一的也不行(比如in.setType("leo.android.cursor.dir/vnd.google.leo");),需要有一個(gè)action配合
可以有多個(gè)mimeType,在java代碼里只需匹配其中一個(gè)即可:
<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>
這樣可以啟動(dòng)MyActivityTwo這個(gè)Activity:
Intent in = new Intent();
in.setAction("android.intent.action.VIEW");
in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因?yàn)镃ategory默認(rèn)值即系Intent.CATEGORY_DEFAULT
in.setType("leo.android.cursor.dir/vnd.google.liao");
startActivity(in);
或者這樣也可以啟動(dòng)MyActivityTwo這個(gè)Activity:
Intent in = new Intent();
in.setAction("android.intent.action.VIEW");
in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因?yàn)镃ategory默認(rèn)值即系Intent.CATEGORY_DEFAULT
in.setType("leo.android.cursor.dir/vnd.google.leo");
startActivity(in);
scheme和mimeType只能有其中一個(gè),下面這樣通不過(guò)
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) 一個(gè)Activity里可以有多對(duì)<intent-filter></intent-filter> 只要匹配其中一對(duì),即可啟動(dòng)這個(gè)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代碼里:
匹配第一對(duì)<intent-filter> 可以啟動(dòng)MyActivityTwo這個(gè)Activity:
Intent in = new Intent();
in.setAction("android.intent.action.VIEW");
in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因?yàn)镃ategory默認(rèn)值即系Intent.CATEGORY_DEFAULT
Uri uri = Uri.parse("something://project.example.com:80");
in.setData(uri);
startActivity(in);
匹配第二對(duì)<intent-filter> 也可以啟動(dòng)MyActivityTwo這個(gè)Activity:
Intent in = new Intent();
in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因?yàn)镃ategory默認(rèn)值即系Intent.CATEGORY_DEFAULT
in.setAction("android.intent.action.VIEW");
in.setType("leo.android.cursor.dir/vnd.google.leo");
startActivity(in);
匹配第三對(duì)<intent-filter> 也可以啟動(dòng)MyActivityTwo這個(gè)Activity:
Intent in = new Intent();
in.setAction("hello.hi.liao");
in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因?yàn)镃ategory默認(rèn)值即系Intent.CATEGORY_DEFAULT
startActivity(in);
全部總結(jié):
1. <action/>包含在 <intent-filter></intent-filter> 標(biāo)簽對(duì)里,而且是必不可少的!不管以哪一種方式來(lái)匹配,都不可缺少這個(gè)<action/> ,可以有多個(gè),至少要有一個(gè)。
如有多個(gè)的,話只需要匹配其中一個(gè)即可找到這個(gè)activity
<action>里的屬性值大多數(shù)是在Intent里定義的,比如<action android:name="android.intent.action.VIEW"/>里的屬性值就等于 Intent.ACTION_VIEW,
在這個(gè)Intent類里以ACTION開頭定義的常量都是。當(dāng)然,也可以自定義。
2. 任何一個(gè)需要隱式啟動(dòng)的Activity都必須要有這項(xiàng):<category android:name="android.intent.category.DEFAULT"/>
例外情況是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中沒(méi)有必要加入android.intent.category.DEFAULT,當(dāng)然加入也沒(méi)有問(wèn)題
<category>里的屬性值大多數(shù)是在Intent里定義的,比如 <category android:name="android.intent.category.DEFAULT"/>里的屬性值就等于 Intent.CATEGORY_DEFAULT,
在這個(gè)Intent類里以CATEGORY開頭定義的常量都是。當(dāng)然,也可以自定義。
3.一個(gè)Activity里可以有多對(duì)<intent-filter></intent-filter> 只要匹配其中一對(duì),即可啟動(dòng)這個(gè)Activity
4.在<intent-filter></intent-filter>里可以有多個(gè)<data android:mimeType="xxxx"/>,只需匹配其中一個(gè)即可.注意:不可以同時(shí)出現(xiàn)第5點(diǎn)的標(biāo)簽對(duì),即下面這條。
5.在<intent-filter></intent-filter>里可以有多個(gè)<data android:scheme="xxxx" android:host="yyyy" android:port="uuu"/>,只需匹配其中一個(gè)即可。
<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
注意:不可以同時(shí)出現(xiàn)第4點(diǎn)的標(biāo)簽對(duì),即上面那條。
6.在<intent-filter></intent-filter>里可以有多個(gè)<action android:name="xxxx"> ,只需匹配其中一個(gè)即可。
7.當(dāng)匹配不上任何Activity的話,會(huì)發(fā)生異常,跳出對(duì)話框:很抱歉...某某應(yīng)用程序意外停止,請(qǐng)重試。
8.上面所說(shuō)的全部適用于Service和BroadcastReceiver,只需把<activity ...></activity>換成<service ...></service>或<receiver ...></receiver>即可。
9.剛參考了一下packages\apps\HTMLViewer\AndroidManifest.xml ,第4和第5條應(yīng)該是不沖突才對(duì),但是實(shí)際測(cè)試中卻是沖突,暫時(shí)未到找原因。匹配方式請(qǐng)看:用于打開HTML文件的intent
在被啟動(dòng)的Activity(本例為MyActivityTwo)里接收數(shù)據(jù):
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();
聯(lián)系客服