魅力程序猿

  • 首页
  • Java
  • Android
  • APP
    • 扑克计分器
    • Video Wallpaper
  • 联系我
  • 关于我
  • 资助
道子
向阳而生
  1. 首页
  2. Android
  3. 正文

Android面试题5--Intent和IntentFilter的匹配规则

2016年11月24日 6833点热度 0人点赞 4条评论

这个问题,一般都会问到,属于高频问题了。做了Android这么多年我也没有弄得很清楚,那这次我们就来仔仔细细的来理一理。

IntentFilter,顾名思义,就是Intent的过滤器。回想一下,好像Intent在我们的代码中出现的频率还是挺高的,是不是也没有特别的去理解它。

先来聊一下Intent

Intent的意思是意图, 而就和它的意思差不多,每当我们使用 Intent的时候,总是去想干一些事情:

startActivity(Intent intent)

startService(Intent intent)

bindService(Intent intent)

sendBrodcast(Intent intent)

.......

对的,我们再很多地方都会使用Intent。对于这些请求,我们都会传入一个Intent,用来Filter并启动相应的Activity、Service、BroadcastReceiver。而在这里,我们就有两种调用方式:显示调用和隐式调用。

显式调用

什么是显示调用呢?那我们用一个启动Activity的例子来说明一下吧:

      Intent _Itent = new Intent();
      _Itent.setClass(ActivitA.this, ActivityB.class);
      startActivity(_Itent);

哎,原来这是显示调用呀。之说以叫做显式调用,我们为Intent清楚的指出了被启动组件的信息(这里就是ActivityB),当调用了startActivity(itent)后,我们就只会很明确的知道,这次的任务是启动ActivityB,而没有其它的过程。

隐式调用

知道了显式调用,应该很容易猜得到了,隐式调用就是没有明确的指出组件信息。而是通过Filter去过滤出需要的组件。还是来个例子说明一下吧:

      Intent _Intent = new Intent();
      _Intent.setAction(Intent.ACTION_BATTERY_LOW);
      _Intent.addCategory(Intent.CATEGORY_APP_EMAIL);
      _Intent.setDataAndType(Uri.EMPTY, "video/mpeg");
      startActivity(_Intent);

这里就是一个隐式的调用,可以看到我为Intent设置了三个属性Action、Category、Data。然后startActivity(intent)就会根据我们设置的这三个属性去筛选合适的组件来打开,也就是因为这样,所以有时候,当我们APP来分享一个东西的时候,会有很多组件(比如QQ、微信、微博...)来供我们选择,因为他们都满足Filter条件。或许你还有许多疑问,来我们就接着来看IntentFilter吧!

再来聊一下IntentFilter及他的匹配规则

IntentFilter的意思就是意图过滤器,当我们隐式的启动系统组件的时候,就会根据IntentFilter来筛选出合适的进行启动。现在我们知道了可以在Intent启动的时候对应设置Action、Category、DataAndType,这里设置的是为了过滤的时候对应IntentFilter匹配action、category、data。除开过滤广播的的IntentFilter可以在代码中创建外,其它的IntentFilter都得在AndroidManifest.xml中给设置。

     Reciver _Reciver = new Reciver();     
     IntentFilter _IntentFilter = new IntentFilter();
     _IntentFilter.addAction(Intent.ACTION_BATTERY_LOW);
     _IntentFilter.addCategory(Intent.CATEGORY_APP_EMAIL);
     _IntentFilter.addDataType("video/mpeg");
     registerReceiver(_Reciver, intentFilter);

这里就是在代码中设置IntentFilter,可以看到我们设置了三个属性。让后我们再看看在AndroidManifest.xml的设置方法:

     <activity  android:name=".ActivityB"    
                android:label="@string/ActivityB"
                android:launchMode="singleInstance">  
                <intent-filter> 
                        <action android:name="android.intent.action.ANSWER" />    
                        <category android:name="android.intent.category.APP_EMAIL" />        
                        <data  android:host="www.aoaoyi.com" 
                               android:port="80"
                               android:scheme="http" />  
                </intent-filter>
     </activity>

我们在这里给Activity设置了一个IntentFilter,但是值得注意的是,一个组件可以有多个IntentFilter,在过滤的时候只要有一个符合要求的,就会被视为过滤通过。

那我们就看看是怎样过滤的吧,首先我们应该明白一个大的思路:当我们隐式的启动一个组件的时候,就会一个一个的去过滤对应组件的全部,(比如你是隐式的启动一个Activity,就会一个一个的在全部Activity中筛选),然后根据Intent的所设置的action、category、data去比较IntentFilter所设置的这三个属性,相同的话就过滤留下来了。

action的匹配

action的匹配要求Intent中的action存在且必须和过滤规则中的其中一个action相同,区分大小写。

首先,action是一个字符串,匹配的话就是说两个action的字符串完全相同(Intent和IntentFilter中的action)。然后我们就看看具体的匹配方法:

。如果IntentFilter中有action,Intent中必须有action

。Intent中的action必须在相应IntentFilter中存在

。Intent中只需要有一个action和IntentFilter中相同即可

IntentFilter中可以设置多个action,Intent中也可以设置多个action,这里就是说我们Intent中的action必须存在IntentFilter中,但是Intent中不必包括IntentFilter中全部的action,但是至少包括一个。

category的匹配

category 要求Intent中可以没有category,但是你一旦有category,不管几个,每个都要和IntentFilter中的category相同。

这里我们说Intent中可以没有category,其实不然,只是在我们启动组件(eg:startActivity( ))的时候,默认给我们的Intent给加了一个category("android.intent.category.DEFAULT" ).

嗯,我们知道了这里,那么匹配就和action差不多了,就是我们的Intent中的category必须在IntentFilter中存在。这里得注意,Intent中都会包括默认的category,并且如果你想隐式启动某个组件,那么就得在IntentFilter中添加android.intent.category.DEFAULT这个category才行。

data的匹配

如果IntentFilter中有定义data,那么Intent中也须也要定义可以匹配的data,平且data数据能够完全比配过滤规则中的某一个data。

聊了上面的两个的匹配规则,发现其实还是很有规律的,对的,data的匹配也差不多(其实我认为是一样的,只是data的结构要复杂些)。

     <data  android:mimeType="text/plain" 
            android:host="www.aoaoyi.com" 
            android:path="/myfolder/my.txt" 
            android:pathPattern="/myfolder/*" 
            android:port="80"
            android:scheme="http" /> 

但其实一个data主要包括的就是一个URI和mimeType。mimeType就是媒体类型,就像"text/plain"这样的,可以表示data是图片呀、文本呀、视频等等。其它的就是URI的了,简单点,就是除开mimeType,剩下的全部都是属于URI的,它们组成了URI。而URI中属性就特别容易懂了,就像host指的是主机名、Scheme指的是URI的模式、Port指的端口号......

在Inten中,我们通过setDataAndType(Uri data, String type)方法对date进行设置。这个方法接受两个参数,第一个就是URI,第二个就是String类型的mimeType了,通过这一个方法,我们就可以给Intent设置data了。、

Scheme:URI的模式,比如Http、file、content等,如果URI中没有指定scheme,那么整个URI的其他参数无效,这也意味着URI是无效的。

Host:URI的主机名,比如www.aoaoyi.com,如果host没有指定,那么整个URI中的其他参数无效,这也意味着URI是无效的。

Port:URI中的端口号,比如80,仅当URI中指定了scheme和host参数的时候port参数才会有意义。

Path、pathPattern、pathPrefix:这三个参数表述路径信息,其中path表示完整的路径信息;pathpatten也表示完整路径信息,但是它的里面可以包含通配符“*”,“*”表示0或多个任意字符,需要注意的是,由于正则表达式的规范,如果想表示真实的字符串,那么“*”要写成“\\*”,“\”要写成“\\\\”;pathPrefix表示路径的前缀信息。

关于data还有一个特殊的情况需要说一下,这也是和action不同的地方,如下两种特殊的写法,他们的作用是一样的。

<intent-filter>

<data android:scheme="file" android:host="www.aoaoyi.com"  />

......

</intent-filter>

<intent-filter>

<data android:scheme="file" />

< android:host="www.aoaoyi.com"  />

......

</intent-filter>

隐式启动的判断

当我们隐式启动的时候,获取无法过滤找到所需要的组件,这样的话就会报错了。那么有没有什么方法来判断隐式启动的Intent是否能找到相应的组件呢?

1、通过PackageManager来判断

       Intent _Intent = new Intent();
       _Intent.setAction(Intent.ACTION_BATTERY_LOW);
       _Intent.addCategory(Intent.CATEGORY_APP_EMAIL);
       _Intent.setDataAndType(Uri.EMPTY, "video/mpeg");
       PackageManager _PackageManager = getPackageManager();
       List<ResolveInfo> _InfoList = _PackageManager.queryIntentActivities(_Intent, PackageManager.MATCH_DEFAULT_ONLY);
       Log.i(TAG, _InfoList.size() + "");
       if (_InfoList.size() != 0) {  
           startActivity(_Intent);
        } else { 
            Log.e(TAG, "没有匹配到Activity");
        }

2、通过Intent的方法:

       Intent _Intent = new Intent();
       _Intent.setAction(Intent.ACTION_BATTERY_LOW);
       _Intent.addCategory(Intent.CATEGORY_APP_EMAIL);
       _Intent.setDataAndType(Uri.EMPTY, "video/mpeg");
       PackageManager _PackageManager = getPackageManager();
       ComponentName _Name =  intent.resolveActivity(getPackageManager());
       if (_Name != null) {  
           startActivity(_Intent);
        } else { 
            Log.e(TAG, "没有匹配到Activity");
        }

 

 

Android面试题6–BroadcastReceiver(广播)

 

标签: Intent IntentFilter的匹配规则 Intent和IntentFilter的匹配规则 显示调用 隐式调用
最后更新:2016年11月24日

daozi

这个人很懒,什么都没留下

点赞
< 上一篇
下一篇 >

文章评论

  • Dreama

    That's a slick answer to a chnalengilg question

    2016年12月18日
    回复
  • Dillian

    This is way more helpful than annhityg else I've looked at.

    2016年12月19日
    回复
  • no man's sky steam key generator

    This is good. Thanks!

    2017年9月26日
    回复
  • vmix 19 crack

    This is good. Thanks!

    2017年9月28日
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    回复 Dreama 取消回复
    搜索
    联系方式

    QQ群:179730949
    QQ群:114559024
    欢迎您加入Android大家庭
    本人QQ:136049925

    赐我一丝安慰
    给我一点鼓励

    COPYRIGHT © 2023 魅力程序猿. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang

    豫ICP备15000477号