activity的启动分为隐式和显示启动,显示调用需要定义启动activity的包名和类名,而隐式调用需要在 Mainifest文件中定义intentFilter过滤规则,activity才能够被启动。activity既可同时定义显示调用或者隐式调用规则,二者共存的话显示为主。
隐式调用需要用到过滤规则如下。
- action匹配
action定义了需要匹配的字符串,系统中会默认有很多action,例如<action android:name="android.intent.action.SEND"/>
,action使用需要在intent的构造函数中传入Intent intent = new Intent("com.myaction.1");
<activity android:name=".Main2Activity">
<intent-filter>
<action android:name="com.myaction.1"/>
<action android:name="com.myaction.2"/>
<category android:name="com.mycategoty.1"/>
<category android:name="com.mycategoty.2"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="myfile/a"
android:scheme="file"/>
</intent-filter>
</activity>
action的匹配规则要求intent必须有一个action,且intent中的action 必须和Mainifest中定义的action完全相同(无论Mainifest有几个action,有一个能匹配上即可)。
- category匹配
categoty的匹配规则要求intent中可以有一个或者多个category也可以没有。但intent中如果定义了多个category匹配规则,那么intent中定义的所有categoty都要匹配上才可启动(无论有几个category,有了就要必须所有能匹配上)。categoty的使用需要调用intent.addCategory("com.mycategoty.1");
addCategory的源码可以看到,通过一个list去维护category。
public @NonNull Intent addCategory(String category) {
if (mCategories == null) {
mCategories = new ArraySet<String>();
}
mCategories.add(category.intern());
return this;
}
- data匹配
data可定义的内容如下
data包含两个主要部分,mimeType以及uri,mimeType指媒体类型,例如本地的图片、音乐等,uri包含的内容有
<scheme>://<host>:<port>/[<path>|<pathPattern|pathPrefix>]
其中 scheme表示资源类型,可以是http、content、file等类型,host为主机名、port为端口、path为资源路径完整信息,pathPatern是可以包含通配符的路径,pathPrefix为前缀。
匹配规则和action类似,同样有一个可匹配的即可。
- 测试
当我们使用如下intent启动上边过滤规则的activity时
Intent intent = new Intent("com.myaction.1");
intent.addCategory("com.mycategoty.1");
intent.addCategory("com.mycategoty.3");
intent.setDataAndType(Uri.parse("file://myfile"), "myfile/a");
startActivity(intent);
系统会崩溃,崩溃日志如下:
09-18 15:14:17.461 19681-19681/sunhailong01.myandroidp E/AndroidRuntime: FATAL EXCEPTION: main
Process: sunhailong01.myandroidp, PID: 19681
android.content.ActivityNotFoundException: No Activity found to handle Intent { act=com.myaction.1 cat=[com.mycategoty.1,com.mycategoty.3] dat=file://abc typ=text/plain }
at android.app.Instrumentation.checkStartActivityResult(Instrumentation.java:1809)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1523)
at android.app.Activity.startActivityForResult(Activity.java:4018)
at android.app.Activity.startActivityForResult(Activity.java:3979)
at android.app.Activity.startActivity(Activity.java:4302)
at android.app.Activity.startActivity(Activity.java:4270)
at sunhailong01.myandroidp.MainActivityPerformClick.run(View.java:21559)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:207)
at android.app.ActivityThread.main(ActivityThread.java:5856)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:933)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:782)
可以看到没有匹配到activity。
- 注意
如果过滤规则中,三种规则都有,那么intent中就需要定义与之匹配的三种规则才可启动,特别的如果在mainfest中指定了<category android:name="android.intent.category.DEFAULT"/>
则在intent中不指定category也可以,因为调用startActivity(intent);
会默认为intent增加一个category。
网友评论