Intent分为显示Intent和隐式Intent.
注意, 为了安全性, 系统只允许通过显示Intent去启动Service, 而且不允许为Service指定IntentFilter.
对于Intent来说, setAction中的字符串, 建议使用包名做为前缀, 但是没有强制要求.
可以通过setData(Uri)来给Intent设置数据, 这个数据是要交给Intent的处理者来处理的, 比如一个Intent要ACTION_EDIT, 那么这个数据就应该是要包含待处理的文档的URI. 不仅要给Intent设置Uri, 一般还要通过setType来给Intent设置MIME type.
注意,如果我们想要同时设置URL和MIME, 请调用setDataAndType方法, 不要单独调用setData和setType方法, 因为这两个方法会相互抵消掉彼此的值.
Intent在解析的时候, Extra不影响Intent的解析, 也就是说两个Intent其他部分一样, 但是Extra不一样, 也会被认为是同一个Intent来处理. 可以使用putExtra和putExtras来添加Extra. Extra的键也应该由包名开始.
对于隐私Intent而已, 可能没有任何一个应用可以处理这个Intent, 这时候我们的应用就会崩溃, 所以在发送隐式Intent之前, 我们应该调用
resolveActivity
来判断是否有应用可以处理这个Intent, 如果结果为空, 我们就不应该发送这个Intent. 比如
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_TEXT,"hello world");
intent.setType("text/plain");
if(intent.resolveActivity(getPackageManager) != null){
startActivity(intent);
}
如果有多个Activity可以处理这个Intent, 默认情况下会弹出一个对话框让用户选择, 用户还可以选择把某一个应用做为默认处理这个Intent的应用.
但是在某些情况下, 我们不希望用户采用默认的这个应用, 比如分享一个图片, 这个时候我们就需要使用 对话框选择器.
通过createChooser()
来创建的Intent会始终调用出来选择对话框.
比如
Intent intent = new Intent(Intent.ACTION_SEND);
//设置选择对话框的标题
String title = getResource().getString(R.string.title);
//看起来是又包装了一层的
Intent chooser = Intent.createChooser(intent, title);
if(intent.resolveActivity(getPackageManager) != null){
startActivity(chooser);
}
这样就会始终弹出对话框让用户选择应用.
Activity生命接收隐式Intent
通过IntentFilter来声明. <intent-filter>有三个元素.
<action>,<data>把一个Uri才分为各个方面(scheme, host, port, path, mime),<category>,
为了能够接受隐私Intent, <category>中必须包含CATEGORY_DEFAULT
.
比如
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
一个Intent必须都通过<action>,<data>,<categroy>三部分的测试, 才会被传递给这个Activity.
由于一个<intent-filter>可能有多个<action>,<data>,<category>标签, 我们看一下这个测试的规则.
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<action android:name="android.intent.action.SEND_MULTIPLE"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google.panorama360+jpg"/>
<data android:mimeType="image/*"/>
<data android:mimeType="video/*"/>
</intent-filter>
对于<action>来说, 只要有一个<action>匹配上了, 就通过action测试. 如果这个<intent-filter>没有<action>, 则任何包含了action的Intent都无法通过测试, 只有不包含action的Intent可以通过测试.
对于<category>来说, 如果<intent-filter>中包含了多个<category>, 比如五个, 但是Intent中只有三个category, 只要这三个category都包含在那五个<category>中, 就可以通过测试. 也就是说Intent声明的每一个category都能在<intent-filter>中找到, 就可以通过测试. 如果Intent没有声明category, 则可以通过所有的category测试.
<data>测试稍微复杂一点, <data>包含了Uri和MIME, uri又被分为scheme, host, port, path四部分, 比如
<data android:mimeType="video/mpeg" android:scheme="http" ... />
<data android:mimeType="audio/mpeg" android:scheme="http" ... />
这四部分存在线性依赖关系, 比如scheme://host:port/path
.
如果没有指定scheme, 会忽略host
如果没有指定host, 会忽略port.
如果没有指定scheme和host, 会忽略path.
如果Intent可以匹配<intent-filter>中的任何一个<data>, 则会通过data测试.
data匹配包含两部分, 一部分是MIME匹配, 一部分是URI匹配. 会先进行MIME匹配, 通过MIME匹配后在进行URI匹配, 两种都匹配通过才算是通过.
MIME匹配规则如下:
<intent-filter>中不包含<data>, 那么Intent中也不能包含data, 如果包含了就不通过匹配.
<data>中不包含MIME, Intent中也不包含MIME, 才会通过MIME匹配.
<data>中包含MIME, 只有当Intent中的MIME一样的时候, 才会通过MIME匹配
通过MIME匹配之后, 还要通过Uri匹配, URI匹配规则如下:
URI的匹配原则是拿Intent中的data和<intent-filter>中的对比, 能匹配上就可以, 所以<intent-filter>中的内容可以比Intent中data的内容多. 也就是说Intent中的URI信息必须都包含在<intent-filter>中才会通过URI匹配(类似于categroy匹配)
如果Intent中包含了scheme, 它就会和<intent-filter>中的scheme对比, 一样的话就通过测试.
如果Intent中包含了scheme和host, 则会和<intent-filter>中的scheme,host进行对比, 都一样就通过测试.
如果Intent中包含了scheme,host, path, 则<intent-filter>中的scheme,host, path一样才会通过测试. 注意<intent-filter>中的path可以使用通配符*
.
系统假定所有的<intent-filter>都支持content:
和file:
这两个scheme, 所以如果Intent中的Uri是以content和file开头的, 如果已经MIME匹配上了, 但是<intent-filter>中没有指定Uri, 则该Intent自动通过URI匹配.
网友评论