隐式意图和intentFilter匹配

隐式意图

  隐式意图:在程序中没有为Intent对象的mComponent属性明确指出想要其启动组件。
  隐式意图仅仅是为Intent对象指出一些筛选条件,然后Android系统会取出Intent对象中的数据和所有已经注册到系统中的组件进行匹配。

-  若匹配成功,则系统将激活该组件。
-  若有多个组件匹配成功,则系统将弹出一个对话框,要求用户选择所要激活的组件。
-  若没有任何组件匹配成功则抛异常。

  应用程序中定义的Android组件都需要在AndroidManifest.xml文件中记录。当系统在进行意图匹配时,就会取出Intent对象中的筛选条件与所有已注册到系统中的各个组件的<intent-filter>标签下定义的数据进行匹配。

  上面所说的“筛选条件”指的就是Intent对象以下三个方面:

1、动作(mAction)
2、数据(mData和mType)
3、分类(mCategories)

  也就是说,我们通过为Intent的上面四个属性赋值,来执行“设置筛选条件”,然后操作系统也会读取这四个属性,并用它们进行匹配。


动作
  mAction:是String类型的,用来告诉系统本次请求要执行什么样的动作。如:张三看书、李四唱歌中的“看”“唱”就是指动作。在Android中内置的动作有很多,常见的有:

-  Intent.ACTION_VIEW :“查看”动作。
-  Intent.ACTION_EDIT :“编辑”动作。
-  Intent.ACTION_DELETE :“删除”动作。
-  Intent.ACTION_CALL:“呼叫”动作,通常指打电话。
-  Intent.ACTION_MAIN :标记当前Activity是程序的入口。


数据
  数据:“动作”所要操作的数据,显然不同的动作要跟不同的数据规范类型配合使用,比如:

-  如果动作是ACTION_VIEW,那么数据就应该指向一个可被查看的东西,比如网页、图片、视频等。
-  如果动作字段是ACTION_EDIT,那么它的数据应该指向它所要编辑的数据。
-  如果动作是ACTION_CALL,那么数据就应该是一个呼叫号码。

  再具体点说,数据包括两部分:mDatamType

-  数据的URI(mData):用来指出数据所在的位置。如file:///tmp/android.txt。
-  数据的类型(mType):用来指出数据的MIME类型。如:text/html 。


分类
  mCategories“动作”的附加信息(可以有多个)。在Android中内置的类型有:

-  Intent.CATEGORY_LAUNCHER :目标Activity能够被列在应用程序启动器上。
-  Intent.CATEGORY_BROWSABLE :目标Activity能够安全的调用浏览器来显示链接所指向的数据(如图片或电子邮件)。
-  Intent.CATEGORY_HOME :目标Activity显示在主屏幕上。


IntentFilter类

  通过前面的介绍,我们已经知道这三点:

-  创建完Activity等组件后,还需要在清单文件中配置它们,以便让系统知道这些组件的存在。
-  在配置它们的时候,除了ContentProvider之外的另外三个组件都可以配置一个或多个<IntentFilter>,它表示过滤器。
-  当我们需要启动一个组件时,整个流程是这样的:
   -  首先,我们创建一个Intent对象,然后将它传递给操作系统。
   -  然后,系统会检测Intent,若它是显式意图的直接启动目标组件,否则会依据Intent内部的信息进行匹配。
   -  接着,如果我们调用的startActivity来启动组件,那么系统会获取当前所有注册到系统中的Activity,并获取它们的<IntentFilter>。
   -  最后,让Intent对象和这些Activity的<IntentFilter>进行匹配,匹配成功就会启动该Activity,若有多个Activity都匹配成功,则系统会让用户选择启动哪一个。
   -  另外,组件可以有多个<IntentFilter>标签,只要该组件有一个匹配成功,则就能启动。

  IntentFilter类与<IntentFilter>标签对应,它有类似于Intent对象的动作、数据、和分类字段。


Action匹配
  在清单文件中的<intent-filter>元素内的<action>子元素对应咱们前面说的“动作”。如:

     
     
1
2
3
4
5
     
     
<intent-filter>
<action android:name="com.example.project.SHOW_CURRENT" />
<action android:name="com.example.project.SHOW_RECENT" />
<action android:name="com.example.project.SHOW_PENDING" />
</intent-filter>
语句解释:
-  像本例显示的这样,一个过滤器可以列出多个Action。但这个列表不能是空的,一个过滤器必须包含至少一个<action>元素,否则它不会匹配任何Intent对象。
-  要通过这个检测,在Intent对象中指定的Action必须跟这个过滤器的动作列表中的某个Action一致匹配。

  
  进行意图匹配时,只有在Intent的mAction属性与<intent-filter>下的某个<action>标签的值匹配成功后,才会去匹配mCategories属性。


Category检测
  <intent-filter>元素内的<category>子元素对应前面说的“分类”。例如:

     
     
1
2
3
4
     
     
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
</intent-filter>

  对于一个要通过Category检测的Intent对象,在Intent对象中所包含的每个分类,过滤器中都必须得包含,过滤器能够列出Intent中不包含的分类,但是它不能忽略Intent对象中的任何分类。
  因此,原则上一个没有categoryIntent对象应该始终通过这个检测,而不管过滤器中声明的分类。

  注意:

-  所有传递给startActivity()方法的隐式Intent对象,都会至少包含了一个android.intent.category.DEFAULT-  只有Intent对象的mCategorie里的所有类型都匹配成功后,才会去匹配<data>标签。


Data检测
  像ActionCategory检测一样,针对IntentFilter的“数据”也要包含在一个子元素中,这个子元素能够出现0~n次。例如:

     
     
1
2
3
4
     
     
<intent-filter>
<data android:mimeType="video/mpeg" android:scheme="http" />
<data android:mimeType="audio/mpeg" android:scheme="http" />
</intent-filter>

  每个<data>元素能够指定URI和数据类型(MIME)对于每个URI部分都会有独立的属性:scheme、host、port、path。格式:

     
     
1
     
     
<scheme>: //<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

  例如,以下URI:

     
     
1
     
     
content: //com.example.project:200/folder/subfolder/etc
-  scheme是content
-  host  是com.example.project
-  port  是200
-  path  是folder/subfolder/etc。

  其中hostport一起构成了authority,如果没有指定host,那么port也会被忽略。


开始匹配

  范例1:新建Activity。

     
     
1
2
3
4
5
6
     
     
<activity android:name="org.cxy.intent.SecondActivity">
<intent-filter>
<action android:name="act.second"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>

  在MainActivity中书写如下跳转语句:

     
     
1
2
3
     
     
Intent intent = new Intent();
intent.setAction( "act.second");
this.startActivity(intent);
语句解释:
-  本范例并没有为Intent指定具体要跳转到哪个Activity,而是为Intent指定一个action。
-  在调用startActivity方法启动Activity时,该方法会自动为Intent对象设置一个category,即:“android.intent.category.DEFAULT”。


  范例2:data匹配。

     
     
1
2
3
4
5
6
7
     
     
<activity android:name="org.cxy.intent.SecondActivity">
<intent-filter>
<action android:name="org.cxy.action.Second"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http" android:host="www.cxy.com" android:port="80" android:path="/hi.jsp"/>
</intent-filter>
</activity>

  在MainActivity中书写如下跳转语句:

     
     
1
2
3
4
     
     
Intent intent = new Intent();
intent.setAction( "org.cxy.action.Second");
intent.setData(Uri.parse( "http://www.cxy.com:80/hi.jsp"));
this.startActivity(intent);
语句解释:
-  使用scheme属性匹配代码中的协议名。
-  使用host属性匹配代码中的主机名,使用此属性之前,必须要先指定scheme属性,在代码中scheme和host之间要写上“://”作为间隔。 
-  使用port属性匹配代码中的端口号,使用path属性匹配代码中的路径。


  范例3:数据类型匹配。

     
     
1
2
3
4
5
6
7
8
     
     
<activity android:name="org.cxy.intent.SecondActivity">
<intent-filter>
<action android:name="org.cxy.action.Second"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http" android:host="www.cxy.com" android:port="80"
android:path= "/hi.jsp" android:mimeType= "image/gif"/>
</intent-filter>
</activity>

  在MainActivity中书写如下跳转语句:

     
     
1
2
3
4
     
     
Intent intent = new Intent();
intent.setAction( "org.cxy.action.Second");
intent.setDataAndType(Uri.parse( "http://www.cxy.com:80/hi.jsp"), "image/gif");
this.startActivity(intent);
语句解释:
-  使用mimeType属性可以对数据的MIME类型进行限制。
-  使用setData方法设置Intent的Uri,使用setType方法设置Intent的MIME类型。
-  但是如果你想同时设置这两者,则只能使用setDataAndType方法,因为setData和setType方法中会彼此清除对方的值,具体请查看源码。


  在<intent-filter>中可以不列出<data>元素,但是只要列出了,那么<data>中所列出的所有属性都得匹配。


  范例4:假设我们有如下配置:

     
     
1
2
3
4
5
6
7
     
     
<activity android:name=".B">
<intent-filter>
<action android:name="aa.test.BBBBBB"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/*"/>
</intent-filter>
</activity>

  那么我们可以用如下代码进行匹配:

     
     
1
2
3
4
     
     
Intent intent = new Intent();
intent.setAction( "aa.test.BBBBBB");
intent.setDataAndType(Uri.parse( "content://abc"), "image/png");
startActivity(intent);
语句解释:
-  也就是说,虽然我们没有为<data>元素设置scheme属性,但是它却存在默认值,会默认匹配“file”、“content”。
-  另外,在<data>元素的path和mimeType属性的值中,都可以包含通配符“*”,用来匹配0~n个任意字符。


  范例5:安装应用程序。

     
     
1
2
3
4
     
     
Intent intent = new Intent(Intent.ACTION_VIEW);
// Uri.fromFile()方法根据文件对象的路径来构造一个Uri。
intent.setDataAndType(Uri.fromFile( file), "application/vnd.android.package-archive");
startActivity(intent);
语句解释:
-  本范例使用系统内置的ACTION_VIEW动作安装APK文件。
-  ACTION_VIEW动作所要操作的数据的Uri是通过一个File对象的路径构造出来的。
-  ACTION_VIEW动作用于“查看”,该动作会根据其所要查看的数据的MIME类型的不同,来调用不同的应用程序来查看数据。
-  APK文件的MIME类型为application/vnd.android.package-archive ,而查看APK文件,其实就是安装APK文件。


  范例6:卸载应用程序。

     
     
1
2
3
4
     
     
Intent intent = new Intent();
intent.setAction(Intent.ACTION_DELETE);
intent.setData(Uri.parse( "package:"+ this.getPackageName()));
startActivity(intent);
语句解释:
-  调用系统内置的ACTION_DELETE动作可以执行删除操作。
-  若删除的数据为:“package:应用程序包名”,则相当于卸载该应用程序。 
-  调用Activity的getPackageName()方法可以获取当前应用程序的包名称。


  范例7:启动发送短信Acitivity。

     
     
1
2
3
4
5
6
7
8
     
     
Intent intent = new Intent();
// 设置意图的动作为“发送”和“发送数据”的MIME类型。
intent.setAction(Intent.ACTION_SEND);
intent.setType( "text/plain");
// 设置要发送的 正文数据。
intent.putExtra(Intent.EXTRA_TEXT, "Hi 发送短信哦!");
startActivity(intent);
语句解释:
-  程序运行时会打开系统发送短信界面。


扩展:

当我们使用隐式意图启动一个A时,可以做一下判断,看是否有A能够匹配我们的隐式意图,如果不判断就有可能因找不到而报错。

所以我们采用:
  PackageManager类中有一组query…()以及resolve…()方法。
  前者返回能够接受一个特殊Intent对象的所有组件,后者返回最佳匹配结果(即只返回1个结果),例如:

-  queryIntentActivities(Intent intent,int flags)方法返回能够执行这个Intent对象的所有Activity
第二个参数我们使用:MATCH_DEFAULT_ONLY 这个表示仅仅匹配那些intent-filter中声明的
<category android:name="android.intent.category.DEFAULT"/>的Activity。因为不含有Default的那些Activity是无法接受隐式意图。
-  queryIntentServices()方法类似地返回Service列表。
-  queryBroadcastReceivers()方法类似地返回Broadcast Receiver列表。

  这些方法都不激活组件,它们只是列出能够响应这个Intent对象的所有组件。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值