隐式Intent 你又知多少?

来源:互联网 发布:电动汽车充电软件 编辑:程序博客网 时间:2024/05/20 11:24

大家常用Intent 用来干什么?没错大概就是启动Activity,Service还有发送Broadcast。OK,首先说说intent的类型

Intent分为2种类型:

显式和隐式

显式Intent比较常见就不多说,通常是因为你知道自己的Activity和Service的类名然后直接调用。

那么隐式Intent呢?其实大家也经常用,就是调用系统相机或者相册的时候,我们都是用隐式Intent来调用的。

创建隐式Intent,我们需要在(manifests)清单文件中给对应的Activity声明Intent过滤器,这里值得注意的是Android系统会对你手机所用应用中的清单文件中声明的Intent过滤器就行比较进启动该组件,如果有多个匹配上就会弹出一个窗口让你选择要使用的应用。

什么是Intent过滤器呢?首先你得先认得<intent-filter> </intent-filter>这个标签,不记得没关系下面这段代码总会知道吧

 <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN"/>                <category android:name="android.intent.category.LAUNCHER"/>            </intent-filter>        </activity>

他的作用就是声明应用的入口。




隐式 Intent 如何通过系统传递以启动其他 Activity 的图解:[1] Activity A 创建包含操作描述的Intent,并将其传递给startActivity()。[2] Android 系统搜索所有应用中与 Intent 匹配的 Intent 过滤器。 找到匹配项之后,[3] 该系统通过调用匹配 Activity(Activity B)的onCreate()方法并将其传递给 Intent,以此启动匹配 Activity。

为了匹配过滤列表,需要同时匹配过滤列表中的action、category、data信息,否则匹配失败。一个过滤列表中的action、category、data可以有多个,所用的action、category、data费别构成不同的类别,同一类别的信息共同约束当前类别的匹配过程、只有一个Intent同时匹配action类别、category类别、data类别才算完美匹配,只有完美匹配才能成功启动目标Activity。另外一点,一个Activity钟可以有多个intent-filter,一个Intent只要能匹配任何一组intent-filter即可成功启动对应的Activity。

要声明应用可以接收哪些隐式 Intent,请在清单文件中使用 <intent-filter>元素为每个应用组件声明一个或多个 Intent 过滤器。每个 Intent 过滤器均根据 Intent 的操作、数据和类别指定自身接受的 Intent 类型。 仅当隐式 Intent 可以通过 Intent 过滤器之一传递时,系统才会将该 Intent 传递给应用组件。每个 Intent 过滤器均由应用清单文件中的<intent-filter> 元素定义,并嵌套在相应的应用组件(例如,<activity> 元素)中。 在<intent-filter> 内部,您可以使用以下三个元素中的一个或多个指定要接受的 Intent 类型:

<action>
name 属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。
<data>
使用一个或多个指定数据 URI 各个方面(schemehostportpath等)和 MIME 类型的属性,声明接受的数据类型。
<category>
name 属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。

下面说一下个属性的匹配规则:

1、action

action是一个字符串,系统预定义了一些action,同时我们也可以自己自定义action。action的匹配规则是Intent中的action必须能够和Intent过滤器<intent-filter> </intent-filter>中的action匹配,这里说的匹配是指action的字符串完全一样(PS:action是区分大小写的,大小写不同字符串相同的action会匹配失败),而Intent过滤器中是可以有多个action的,那么就是说 Intent中的action存在且必须和过滤器中的其中一个acting相同,那么就匹配成功。

2、category

category也是一个字符串,系统也预定义了一些category,同时我们也可以在应用中自定义一些自己的category。你可以不设置category因为上面说过方法 startActivity() 和 startActivityForResult() 将按照已申明 CATEGORY_DEFAULT 类别的方式处理所有 Intent。但是你要使用隐式Intent的话那必须将 CATEGORY_DEFAULT 类别包括在 Intent 过滤器中。如果Intent设置了category,不管设置了几个category,每一个category必须和Intent过滤器中的category一一对应上,否者匹配不成功。

3、data

data与action类似,如果Intent过滤器中设置了data那么Intent中必须定义可匹配的data,而data稍微有点复杂,请让我徐徐道来。

首先data的语法如下:

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

data 由两部分组成,mimeType和URI。mimeType指的是媒体类型,比如image/png,video/*,可以表示图片,视频,文本等媒体类型,而URI中包含的数据比较多,下面是URI的结构:

<scheme>://<host>:<port>/[<path>|<pathPrefix>|<pathPattern>]

这里给例子比较好理解:

content://com.example.projoct:5144/folder/........

http://www.baidu.com:8080/search/abc........

那么接下来还是要说一下每一项的意义:

Scheme:URI的模式,比如http、file、content等,如果URI没有指定Scheme,那么整个URI的其他参数无效,这就是说URI本身也无效了。

Host:URI的主机名,比如www.baidu.com,如果host没有指定,那么整个URI中的其他参数无效,这就是说URI本身也无效了。

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

Path、pathPattern和pathPrefix:这三个参数表述路径信息


data的匹配规则大体分为4种情况:[1]没有指定URI和mimeType [2]指定了URI没有指定mimeType [3]没有指定URI指定mimeType [4]指定URI和mimeType。

[1] 当Intent 没有设置setData 同时 Intent过滤器没有设置<data></data>时,匹配成功。

[2] 当Intent 设置setData(Uri.parse("content://......")) 没有设置mimeType 同时 Intent过滤器Uri一样且没有设置android:mimeType=""时,匹配成功。

[3] 当Intent 设置setType("image/*") 没有设置setData 同时Intent过滤器android:mimeType=""一样且没有设置时Uri时,匹配成功。

[4] 当Intent 设置setDataAndType(Uri.parse("hehe://com.example.hehe:5144/folder/"),"image/*");,同时Intent过滤器定义了android:mimeType="image/*"
android:host="com.example.hehe"   android:scheme="hehe"   android:port="5144"时,匹配成功。

[5]特殊情况

<intent-filter>    <data android:mimeType="image/*" />    ...</intent-filter>

这种规则制定了媒体类型为所有类型的图片,那么Intent中的mimeType属性必须为“image/*”,才能匹配,这种情况下虽然Intent-过滤器 没有制定URI,但是却有默认值的,URI的默认值content或者file才能匹配。

intent.setDataAndType(Uri.parse("file://com.example.projoct:5144/folder/abc"),"image/png");

如果

<intent-filter>    <data android:scheme="http" android:type="video/*" />    ...</intent-filter>

那么

intent.setDataAndType(Uri.parse("http://abc"),"video/mpeg");

另外如果要设置完整的Data和Type就必须得调用setDataAndType方法:

  public Intent setData(Uri data) {        mData = data;        mType = null;        return this;    }

 public Intent setType(String type) {        mData = null;        mType = type;        return this;    }

我们从源码中不难看出无论是单独setData还是setType都会把另外一个清空。

最后,当我们通过隐式方式启动一个Activity的时候可能会因为找不到对应的Activity而报错,所以我们可以先用PackageManagerresolveActivity()来判断是否为空

Intent intent = new Intent(Intent.ACTION_VIEW);intent.setDataAndType(Uri.parse(url), mimetype);if (getPackageManager().resolveActivity(intent,PackageManager.MATCH_DEFAULT_ONLY) != null) {startActivity(intent);}

PackageManager.MATCH_DEFAULT_ONLY 这个标记为的含义是仅仅匹配那些<intent-filter> </intent-filter>声明了

<category android:name="android.intent.category.DEFAULT" />

这个的Activity,因为不含有DEFAULT这个category的Activity无法接受隐式Intent。


下面是一个网页调用App的一个例子:


        <activity android:name=".MainActivity">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>            <intent-filter>                <category android:name="android.intent.category.DEFAULT"/>                <category android:name="android.intent.category.BROWSABLE"/>                <data                    android:host="usertest.com"                    android:scheme="http"/>            </intent-filter>        </activity>

<category android:name="android.intent.category.BROWSABLE" />
加上这个就能在浏览器点击调用你的app了,再对应网页点击的超链接中加上

<a href="http://usertest.com">test</a>  

参看文档:

https://developer.android.com/guide/components/intents-filters.html点击打开链接



0 0
原创粉丝点击