魅力程序猿

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

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

2016年11月24日 6830点热度 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
    回复 no man's sky steam key generator 取消回复
    搜索
    联系方式

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

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

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

    Theme Kratos Made By Seaton Jiang

    豫ICP备15000477号