Android 开发艺术探索读书笔记(二)

1.3 节主要讲 IntentFilter 的匹配规则。

顾名思义,IntentFilter 就是 Intent 的过滤器。我们都知道,Android 系统中启动 Activity 的方式有两种,显式调用和隐式调用,显式调用就是调用指定名称的 Activity,而隐式调用就需要 IntentFilter 的配合了。通过 IntentFilter 我们可以调用具有指定功能的 Activity,如果有多个 Activity 符合条件,那么系统就会列出所有可用的 Activity 供我们选择。IntentFilter 不仅用于启动 Activity ,还可以用于启动服务和发送广播,但这里我们只关注 Activity 部分。

IntentFilter 中有三种过滤方式,分别为 action、category 和 data,其中 action 表示接受的操作,category 表示接受的类别,data 用来指定 URI 和 MIME 类型,先来个示例:

<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>

上面的代码声明了一个使用 IntentFilter 的 ShareActivity,这样我们就可以使用对应的 Intent 来启动此 Activity。

为了匹配过滤列表,需要同时匹配列表中的 action、category、data 信息,否则匹配失败,一个 Activity 可以有多个 IntentFilter,一个 Intent 只要能匹配任意一个 IntentFilter 即可成功启动 Activity。下面分别介绍一下 action、category 和 data 的匹配规则。

action 的匹配规则

action 是一个字符串,Android 系统中预定义了一些 action,我们也可以自定义 action。一个 Intent 中必须包含 action,action 的匹配规则是 Intent 中的 action 和 过滤列表中任意一个 action 完全匹配(区分大小写),否则匹配失败。

category 的匹配规则

category 也是一个字符串,系统也预定义了一些 category 供我们使用,同时我们也可以自定义 category。Intent 中可以没有 category,但如果有,则 Intent 中的 category 必须和一个 IntentFilter 中的每一个 category 匹配,否则匹配失败。

上面说 Intent 中可以没有 category,其原因是系统在调用 startActivity() 或 startActivityForResult() 的时候会默认帮我们加上 android.intent.category.DEFAULT 这个 category,同时,我们的 Activity 如果想要接收隐式调用,就必须在 IntentFilter 中指定 android.intent.category.DEFAULT。

data 的匹配规则

data 由两部分组成,URI 和 mimeType,语法如下:

<data android:scheme="string"
android:host="string"
android:port="string"
android:path="string"
android:pathPattern="string"
android:pathPrefix="string"
android:mimeType="string" />

其中 URI 的结构为:<scheme>://<host>:<port>[<path>|<pathPrefix>|<pathPattern>],如:

http://www.example.com:80/test/etc

scheme 表示 URI 的模式,host 和 post 分别表示 URI 的主机名和端口号,path 表示一个完整的路径,pathPattern 也表示一个完整的路径,但它可以接收通配符,如 “*” 和 ".*" 等,pathPrefix 表示一个路径的前缀。

URI 格式的这些属性是可选的,但也是相互依赖的,如果 scheme 未指定,则忽略所有其他 URI 属性,即这个 URI 是无效的;如果 host 未指定,则 port 和 path 部分将被忽略,这也意味着这个 URI 是无效的。

data 中如果只有 mimeType 而没有 URI,则 URI 的默认 scheme 属性为 content 和 file,data 的匹配规则和 action 类似,只要和 IntentFilter 中的任意一个 data 完全匹配即可,否则匹配失败。

说完了 IntentFilter 的匹配规则,下面来看一个示例吧:

private void testIntentFilter() {
    Intent intent = new Intent(Intent.ACTION_SEND);
    intent.setDataAndType(Uri.parse("file://abc"), "image/png");
    startActivity(intent);
}

这里要注意一下,如果要为 Intent 指定完整的 data,必须要调用 setDataAndType() 方法,不能分开调用 setData() 和 setType() 方法,因为这两个方法会彼此清除对方的值。

还有一个问题,当我们隐式启动一个 Activity 的时候,如果系统中没有符合条件的 Activity,那么就会出现错误,这通常会导致 app 崩溃,并弹出一个错误对话框,类似 Windows 上的“很抱歉,xxx 已停止运行”,这个讨厌的提示想必大家都见过,Android 中的错误对话框同样令人讨厌,因为没有人喜欢错误。

为了避免错误对话框,我们需要解决这个潜在的问题,在 Intent 类中有一个方法叫 resolveActivity(PackageManager pm),此方法返回最符合 Intent 要求的一个 Activity,如果没有,则返回 null,我们可以根据这个方法的返回值是否为 null 来判断系统中是否有符合要求的 Activity,代码如下:

private void testIntentFilter() {
    Intent intent = new Intent(Intent.ACTION_SEND);
    intent.setDataAndType(Uri.parse("file://abc"), "image/png");
    if (intent.resolveActivity(getPackageManager()) != null) {
        startActivity(intent);
    } else {
        // TODO
    }
}

猜你喜欢

转载自www.cnblogs.com/andorxor/p/9356455.html
今日推荐