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(Activity_A.this, Activity_B.class);
startActivity(itent);
哦,这就是显式调用。之说以叫做显式调用,我们为Intent
清楚的指出了被启动组件的信息(这里就是Activity_B
),当调用了startActivity(itent)
后,我们就只会很明确的知道,这次的任务是启动Activity_B
,而没有其它的过程。
隐式调用
看了显式调用,应该猜都猜得到了,隐式调用就是没有明确的指出组件信息。而是通过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
中给设置。
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_BATTERY_LOW);
intentFilter.addCategory(Intent.CATEGORY_APP_EMAIL);
intentFilter.addDataType("video/mpeg");
Reciver reciver = new Reciver();
registerReceiver(reciver, intentFilter);
这里就是在代码中设置IntentFilter
,可以看到我们设置了三个属性。让后我们再看看在AndroidManifest.xml
的设置方法:
<activity android:name=".Activity_B"
android:label="@string/title_activity_activity__b"
android:launchMode="singleInstance">
<intent-filter>
<action android:name="android.intent.action.ANSWER" />
<category android:name="android.intent.category.APP_EMAIL" />
<data android:host="www.mathiasluo.com"
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中也必须也要定义可以的date
看了上面的两个的匹配规则,发现其实还是很有规律的,对的,data
的匹配也差不多(其实我认为是一样的,只是data
的结构要复杂些)。
<data android:mimeType="text/plain"
android:host="www.mathiasluo.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
了。、
隐式启动的判断
当我们隐式启动的时候,获取无法过滤找到所需要的组件,这样的话就会报错了。那么有没有什么方法来判断隐式启动的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();
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");
}
这里我们是通过PackageManager
来判断的,还有一种Intent
的方法:
Intent intent = new Intent();
intent.setAction(Intent.ACTION_BATTERY_LOW);
intent.addCategory(Intent.CATEGORY_APP_EMAIL);
intent.setDataAndType(Uri.EMPTY, "video/mpeg");
ComponentName name = intent.resolveActivity(getPackageManager());
if (name != null){
startActivity(intent);
}else {
Log.e(TAG,"没有匹配到Activity");
}
这两个方法差不多,也都很简单,所以就不多说了。
最后
还有,这些是我参考《Android开发艺术探索》的,对,就是任大大的。