关于Android隐式启动Activity的分析和说明 Android开发当中我们知道,每个组件可以有一个或者多个intent filter。提到Intent filter我们就来了解下Intent filter,Intent filter有三个部分构成,分别是action,data和category。Intent filter是在Android的主配置文件AndroidManifest.xml中注册,主要用来指明Activity, Service, Broadcast reciver这三个组件可以响应哪些隐式intents。
下面通过代码分析每个部分的功能。
每个action, category, data都是一行,如果有多个就写多行。"android.intent.action.MAIN" and "android.intent.category.LAUNCHER"这两个是程序入口点的filter必须部分。比如说短信这个应用,当你点击MMS的图标程序启动后,映入使用者的一个界面(所有收到的短信列表),这个短信列表界面就是程序的入口点,通俗的讲就是一个application启动后显示的第一个界面。另外,"android.intent.category.DEFAULT"这个category是用来指明组件是否可以接收到隐式Intents,所以说除了程序入口点这个filter不用包含DEFAULT category外,其余所有intent filter都要有这个category。
data有两部分构成,一个是数据类型,另一个是URI。每个URI包括四个属性参数(scheme,host, port, path),形如:scheme://host:port/path
Intent filter和Intent相互配合,实现了Android系统四大组件之间的信使功能。
详细例子说明
举个例子 content://com.examplproject:e.200/folder/subfolder/etc 这个列子中scheme是content,host是com.examplproject,port是200,path是folder/subfolder/etc
更多例子请参考:http://hi.baidu.com/wishwingliao/blog/item/0a38ccfce06f39e8fc037f85.html 隐式启动Activity的intent到底发给哪个activity,需要进行三个匹配,一个是action,一个是category,一个是data,可以是全部或部分匹配 同样适用于Service和BroadcastReceiver,下面是以Activity为例 MainActivity.java --主Activity TestActivity.java --需要隐式启动的Activity (1) 根据Action和Category来进行匹配 在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里注册的属性, 查找到符合这个 intentOther 的就启动这个Activity,如果有多个这样的Activity符合条件的话,就跳出一个对话框让用户选择究竟要启动哪一个 上面那个自定义的Action字符串("cc.android/myaction.leo",当然也可以写成这样"cc.android.myaction.leo",同时AndroidManifest.xml里也要写成这样)是系统唯一的, 所以系统很容易就能匹配到。 b.任何一个需要隐式启动的Activity都必须要有这项: 例外情况是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中没有必要加入android.intent.category.DEFAULT,当然加入也没有问题 c.假如有两个Activity,它们的在AndroidManifest.xml里配置如下: 在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); e.当匹配不上任何Activity的话,会发生异常,跳出对话框:很抱歉...某某应用程序意外停止,请重试。 f.Service和BroadcastReceiver 同理 (2) 根据Action和Data匹配 //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里面指定了这行,那么,需要匹配到它的话,在代码里必须要设置intent的data,如上面的in.setData(uri) Data的语法: 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里这样写: 那么Uri uri = Uri.parse("something://project.example.com"); 才可以匹配 等同于这样写: 那么Uri uri = Uri.parse("something://project.example.com:80"); 才可以匹配 不知为何,下面这个不行: Uri uri = Uri.parse("content://com.example.project:200/folder/subfolder/etc") 下面这样也不行 Uri uri = Uri.parse("content://com.example.project:200/folder") 可以有多个data,只需匹配其中一个即可 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属性匹配 在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代码里只需匹配其中一个即可: 这样可以启动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里: android:port="80" android:mimeType="leo.android.cursor.dir/vnd.google.leo" /> android:port="80" /> 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里可以有多对 只要匹配其中一对,即可启动这个Activity android:port="80" /> java代码里: 匹配第一对 可以启动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); 匹配第二对 也可以启动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); 匹配第三对 也可以启动MyActivityTwo这个Activity: Intent in = new Intent(); in.setAction("hello.hi.liao"); in.addCategory(Intent.CATEGORY_DEFAULT);//可去掉,因为Category默认值即系Intent.CATEGORY_DEFAULT startActivity(in); 全部总结: 1. 包含在 标签对里,而且是必不可少的!不管以哪一种方式来匹配,都不可缺少这个 ,可以有多个,至少要有一个。 如有多个的,话只需要匹配其中一个即可找到这个activity 里的属性值大多数是在Intent里定义的,比如里的属性值就等于 Intent.ACTION_VIEW, 在这个Intent类里以ACTION开头定义的常量都是。当然,也可以自定义。 2. 任何一个需要隐式启动的Activity都必须要有这项: 例外情况是:android.intent.category.MAIN和android.intent.category.LAUNCHER的filter中没有必要加入android.intent.category.DEFAULT,当然加入也没有问题 里的属性值大多数是在Intent里定义的,比如 里的属性值就等于 Intent.CATEGORY_DEFAULT, 在这个Intent类里以CATEGORY开头定义的常量都是。当然,也可以自定义。 3.一个Activity里可以有多对 只要匹配其中一对,即可启动这个Activity 4.在里可以有多个,只需匹配其中一个即可.注意:不可以同时出现第5点的标签对,即下面这条。 5.在里可以有多个,只需匹配其中一个即可。 android:mimeType="string" android:path="string" android:pathPattern="string" android:pathPrefix="string" android:port="string" android:scheme="string" /> 可以分开写,如: 等同于这样写: 在java代码里,Uri的格式:scheme://host:port/path or pathPrefix or pathPattern 注意:不可以同时出现第4点的标签对,即上面那条。 6.在里可以有多个 ,只需匹配其中一个即可。 7.当匹配不上任何Activity的话,会发生异常,跳出对话框:很抱歉...某某应用程序意外停止,请重试。 8.上面所说的全部适用于Service和BroadcastReceiver,只需把换成或即可。 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();
请参考:packages\apps\HTMLViewer\src\com\android\htmlviewer\HTMLViewerActivity.java
|