您的位置:首页 > 文旅 > 旅游 > 重庆沙盘制作_成都市住房与城乡建设局官网_六种常见的网站类型_汕头网站建设优化

重庆沙盘制作_成都市住房与城乡建设局官网_六种常见的网站类型_汕头网站建设优化

2024/12/22 0:43:13 来源:https://blog.csdn.net/jxq1994/article/details/144581310  浏览:    关键词:重庆沙盘制作_成都市住房与城乡建设局官网_六种常见的网站类型_汕头网站建设优化
重庆沙盘制作_成都市住房与城乡建设局官网_六种常见的网站类型_汕头网站建设优化

Intent属性

  • Component Name

Intent可以被分为两类,即显性和隐性。如果我们在Intent中特别指定了目标方的“Component Name”,比如:“com.example.project.HelloActivity”;同时指定它所在的PackageName,如“com.example.project”,那么系统就会直接将此Intent发往这个特定的应用,而不需要做额外的匹配工作。

如果一个应用程序通过这种方式显性调用另一个应用进程,多半是这两个应用程序同属于一家研发公司,或者是同一进程中的两个组件。

  • Category

如果说上面的Component Name是某人的名字,那么Category就好比国籍。Android系统中已经预设了一些“国家”,我们摘录其中的部分核心元素。另外,由于Intent的所有属性值实际上都只是一串字符,因而是可以自定义的。
在这里插入图片描述

  • Action

表明要做什么,或者什么事件发生了(常用于广播的情况。比如设备开机时会有系统广播发出,如果应用程序希望实现开机自启动,就可以监听这个广播)。和Category一样,用户也可以自定义一项唯一的Action,如“com.ThinkingInAndroid.action.example”。Android系统
中预定义的部分常见Action。
在这里插入图片描述

  • data

如果上面的Action中表明了某人去公安局出入境处“办理签证”的“动作”,那么这里的Data就作为“签证”业务的补充材料——比如这个人的名字、身份证件等。所以,Action理论上是围绕Data提供的数据来开展业务的。当然也有不需要Data补充信息的情况,如在ACTION_CALL的情况下,电话号码是必须作为Data来传递的;而针对Broadcast(如ACTION_SCREEN_ON)组件的Action,它们本身就蕴含了足够的信息,因而不需要Data的支持。

  • Extras

Extras可以理解为Extra Data,它是对上面Data属性的补充。不过两者在数据的格式上有明显区别。Data采用了类似scheme://uri的表达方式;而Extras则是一种键值对实现。它们在表达不同场景的数据时有各自的优势,使用者应该“具体问题具体分析”。发送方通过一系列putXXX()方法将键值对存入Intent中,然后接收方就可以用相对应的getXXX()来获取到这些Extra数据。这些方法的内部会维护一个Bundle对象来保证进程间数据的准确传输。

  • Flags

Flags和Activity中的LaunchMode功能基本相同,它规定了系统如何去启动一个Activity(比如指定即将启动的Activity应该属于哪一个Task)。举个例子,如果一开始Task栈从下往上的顺序是A-B-C,随后C通过带有Flag为FLAG_ACTIVITY_CLEAR_TOP的Intent来启动另一个Activity。如果该Activity在栈中已经存在,比如说是B,那么启动后的Task栈就变成了A-B;否则该Activity直接入栈,而不会先清理栈顶。

Intent的匹配规则

Intent是和Intent-filter配套使用的。具体而言,Intent-filter是每个组件的属性标签,它们在AndroidManifest.xml声明时就已经“贴上”了。而Intent则是程序运行过程中产生的实时“需求”。系统接收到这些请求后与现有的Intent-filter进行匹配,然后选择最合适的组件元素以响应。

以“婚介所”为例子,Intent代表了女生的择偶意愿,而Intent-filter则是众男士的属性描述——年龄、长相、收入等。

图1描述了广播BroadcastReceiver的匹配流程,其他组件也类似。
在这里插入图片描述

  1. 组件注册
    当应用程序安装到系统中时,Android会通过扫描它的AndroidManifest文件来得到一系列信息——这其中就包括了它的;而且系统还会根据组件的不同进行相应的细化归类。比如Activity和Service,它们响应Intent的场合是不同的(前者是startActivity,后者则是startService)。换句话说,当某人调用了startActivity后,显然系统只需在所有Activity中做匹配即可,而
    不应该再去考虑Service中的Intent-filter。

  2. 发起方主动向系统提供Intent
    这一步是在程序运行过程中发生的,此时系统已经掌握了所有组
    件的信息。发起方根据自己的需求填写Intent,并按
    照目标方是Activity,Service还是BroadcastReceiver来调用对应的
    函数。如下所示:

Activity→对应startActivity();
Service →对应startService();
BroadcastReceiver→对应sendBroadcast();

系统会严格区分对待这些组件分类。所以利用
startActivity()是绝对不可能启动Service的——即便Intent和
intent-filter能成功匹配。

  1. 系统将Intent和对应组件类型(Activity,Service等)里所有的intent-filter进行匹配,以寻找最佳的结果。

隐性Intent的匹配规则

影响Intent匹配规则的只有3个关键因素,即:

  • Category
  • Action
  • Data (URI和数据类型都要同时匹配)

而其余两个属性Extras和Flags则只有在选中的组件运行后才能起作用。
一个组件可以同时声明多个intent-filter。而在匹配过程中,只要它包含的任何一个filter通过了测试,它就会被选中。

在匹配测试中,系统遵循“子集”的概念。

换句话说,Intent中的3个关键因素至少要是该组件所包含的其中一个
intent-filter的子集(Data有点特殊,下面有详细解释),才能通过
验证,如图2所示。

在这里插入图片描述

  • 每个Component(Activity、Service、BroadcastReceiver)都可以有若干个intent-filter。

  • 每个filter里的上述3种属性都可以不是唯一的。

  • 匹配时,Intent中的3种属性都需要通过测试。

Category匹配规则

  • 如果一个Intent中指定了1到N个category项
    则这个intent对象中的1到N个category,在 xxx 中,需要全有,一一匹配则通过,否则失败;

    注意:<intent-filter >中的category可以比intent对象中的category多,只要intent中的全都匹配到,就可以通过

  • 如果一个Intent中没有指定任何category项
    系统会自动为其添加一个“android.intent.category.DEFAULT”。所以,在这种情况下,如果你想让你的activity接收这些intent对象,就必须在其<intent-filter> 中添加 <category android:name="android.intent.category.DEFAULT" />

注意:如果<intent-filter>里已经带有“android.intent.action.MAIN”和“android.intent.category.LAUNCHER”,就可以不用再另外添加DEFAULT了,这是一个例外。

Action 匹配规则

  • 如果一个Intent中指定了action项

    • 如果这个action至少匹配<intent-filter> xxx </intent-filter>中的一个action,则匹配通过,否则失败;
    • 如果<intent-filter> xxx </intent-filter>中没有任何action项,则直接匹配失败;
  • 如果一个Intent中没有指定任何action项

    • 如果<intent-filter> xxx </intent-filter>中至少有一个action,则匹配通过;
    • 如果<intent-filter> xxx </intent-filter>中没有任何action项,则直接匹配失败;

Data 匹配规则

每个<data>项目都可以指定一个URI和一个MimeType(数据类型)。

<intent-filter><data android:mimeType="video/mpeg" android:scheme="http" ... /><data android:mimeType="audio/mpeg" android:scheme="http" ... />...
</intent-filter>
MimeType

MIMEType的目的很简单,就是指明某段数据是什么格式类型,以保证程序能正确解析处理。比如电子邮件中的附件,如果不特别说明,接收方客户端就没办法知道它们是图片、文本还是应用程序。这样的结果就是用户找不到合适的途径来对附件进行解析。国际标准中已经预设了很多常见的文件类型,举例如下。
在这里插入图片描述

注意:type和subtype中以x-开头的属于非标准格式(未向IANA注
册);而subtype中以vnd开头的则是厂商自定义的(vendorspecific)。

例如:

  • application/vnd.oasis.opendocument.text ##OpenDocument文本
  • application/vnd.ms-excel       ##MicrosoftExcel文件
  • application/x-latex          ##LaTeX文件
  • audio/x-caf             ##Apple公司的CAF音频文件
URI

每个URI都可包含scheme, host, port, path这几属性,其格式为

<scheme>://<host>:<port>/<path>
  • 举例:content://com.example.project:200/folder/subfolder/etc

    • <scheme> 为 content

    • <host>为com.example.project

    • <port>为200

    • <path>为 folder/subfolder/etc

其中,scheme不仅包括了传统的“http”等网络协议,还有“content”来表示本地ContentProvider所提供的数据。
“host”是主机的名称,“port”指明通信的端口,它们统称为“Authority”;而且如果host不存在,后面的端口号也会被忽略。
最后一部分是文件的路径,它是该资源在host中的具体位置。

  • 注意:每个<data>项目中的URI,scheme, host, port, path这几个属性,不是全都需要指定,但有一个线性的依赖要求:

    • 如果<scheme> 没有被指定,则后面的<host>被忽略。
    • 如果<host> 没有被指定,则后面的<port>被忽略。
    • 如果<scheme><host> 都没有被指定,则后面的<path>被忽略。
匹配规则

只有intent-filter中存在的那部分属性(比如某filter中只指定了mimeType,那么只匹配mimeType),才需要进行匹配。

(1)Intent中既没有指定数据类型,也没有填写URI

在这种情况下,只有intent-filter中也同样没有指定数据和URI,才可能
通过测试。

(2)Intent中没有指定数据类型(且无法从URI中推断出),但有
URI。

数据类型有可能从URI中推断出来——如果是就属于第四种情况。前面已经说过,“只有filter中存在的那部分属性,才需要进行匹配”,因而这种情况下仅当其 URI 与的 URI 格式匹配、且同样未指定 MIME 类型时,才可能通过测试。

(3) Intent中只指定了数据类型,没有URI。

这种情况下仅当列出相同的 MIME 类型且未指定 URI 格式时,才可能通过测试。

(4)Intent中同时指定了数据类型(或可以从URI推断出)和URI。

这时数据类型和URI都必须通过测试。具体来说,仅当 MIME 类型与<intent-filter>中列出的类型匹配,同时 Intent 的 URI 与<intent-filter>中的 URI也要 匹配,或者如果 Intent 具有 content: 或 file: URI且<intent-filter>未指定 URI,则 Intent 会通过测试的 URI 部分。

URI匹配规则

  • 如果<intent-filter>中的这个URI只有一个<scheme> ,则Intent对象中拥有相同<scheme>的URI,全部通过。
  • 如果<intent-filter>中的这个URI指定了<scheme><authority> ,但是没有指定<path>,则Intent对象中拥有相同<scheme><authority> 的URI,不管其<path>是什么值,全部通过。
  • 如果<intent-filter>中的这个URI指定了<scheme><authority><path>,则Intent对象中拥有相同<scheme><authority><path>的URI,才能通过。
  • 注意:<path>中可以使用 *通配符

实例

Note Pad Example 记事本

在其manifest文件中, 记事本程序定义了三个activity, 每个有至少一个intent filter. 它还定义了一个content provider来管理笔记数据. manifest 文件如下:

<manifest XMLns:android="http://schemas.android.com/apk/res/android"package="com.example.android.notepad"><application android:icon="@drawable/app_notes"android:label="@string/app_name" ><provider android:name="NotePadProvider"android:authoritIEs="com.google.provider.NotePad" /><activity android:name="NotesList" android:label="@string/title_notes_list"><intent-filter> // NotesList-filter-1<action android:name="android.intent.action.MAIN" /><category android:name="android.intent.category.LAUNCHER" /></intent-filter><intent-filter> //NotesList-filter-2<action android:name="android.intent.action.VIEW" /><action android:name="android.intent.action.EDIT" /><action android:name="android.intent.action.PICK" /><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /></intent-filter><intent-filter> //NotesList-filter-3<action android:name="android.intent.action.GET_CONTENT" /><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="vnd.android.cursor.item/vnd.google.note" /></intent-filter></activity><activity android:name="NoteEditor"android:theme="@android:style/Theme.Light"android:label="@string/title_note" ><intent-filter android:label="@string/resolve_edit"> //NoteEditor -filter-1<action android:name="android.intent.action.VIEW" /><action android:name="android.intent.action.EDIT" /><action android:name="com.android.notepad.action.EDIT_NOTE" /><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="vnd.android.cursor.item/vnd.google.note" /></intent-filter><intent-filter> //NoteEditor -filter-2<action android:name="android.intent.action.INSERT" /><category android:name="android.intent.category.DEFAULT" /><data android:mimeType="vnd.android.cursor.dir/vnd.google.note" /></intent-filter></activity><activity android:name="TitleEditor"android:label="@string/title_edit_title"android:theme="@android:style/Theme.Dialog"><intent-filter android:label="@string/resolve_title"> //TitleEditor -filter-1<action android:name="com.android.notepad.action.EDIT_TITLE" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.ALTERNATIVE" /><category android:name="android.intent.category.SELECTED_ALTERNATIVE" /><data android:mimeType="vnd.android.cursor.item/vnd.google.note" /></intent-filter></activity></application>
</manifest> 

根据上面的AndroidManifest文件,可以看到NotePad共包含了3种Activity,即NotesList(用于显示已经保存的文章),NoteEditor(用于编辑文章)和TitleEditor(用于编辑文章的标题)。

下面我们通过列举几个不同的Intent来分析系统的匹配情况。

  • Intent 1
action: android.intent.action.MAIN
category: android.intent.category.LAUNCHER

Category测试:根据子集原则,只有NotesList-filter-1通过了
检查。
Action测试:依据上面所分析的Action测试第3点,NotesListfilter-1通过了检查。
Data测试:属于第一种情况,即intent里既没有指定类型,也无URI。而另外,filter也是同样的情况,因此根据“只有filter里有的那部分属性才需要检查”的原则,NotesList-filter-1最终通过了匹配。这个Intent1将对应NoteList。

  • Intent 2
action: android.intent.action.VIEW
data: content://com.google.provider.NotePad/notes

Category测试:Intent中没有指定Category,系统会自动为其加上DEFAULT值。因为所有filter都写上了这个默认值,因而全部通过测试。
Action测试:只有NotesList-filter-2和NoteEditor-filter-1通过测试。
Data测试:表面上属于第二种情况,即只指定了URI而没有类型。但实际上从这个例子中的content可以推断出type,因而属于第四种情况。推断出的类型为"vnd.android.cursor.dir/vnd.google.note"(可以参见下一小节对推断过程的源码解析),因而最终通过测试的是NotesList-filter-2。

  • Intent3
action: android.intent.action.GET_CONTENT
data type: vnd.android.cursor.item/vnd.google.note

Category测试:Intent中没有指定Category,系统会自动为其加上DEFAULT值。因为所有filter都写上了这个默认值,因而全部通过测试。

Action测试:只有NotesList-filter-3通过测试。

Data测试:只有Type,而没有URI,属于第三种情况。因为NotesList-filter-3也是同样的情况,而且它们的类型也是匹配的,所以最终通过测试。

  • Intent4
action: android.intent.action.INSERT
data: content://com.google.provider.NotePad/notes

Category测试:同Intent2。

Action测试:只有NotesEditor-filter-2符合要求。

Data测试:同Intent2。

  • Intent5
action: com.android.notepad.action.EDIT_TITLE
data: content://com.google.provider.NotePad/notes/ID

Category测试:同Intent2。

Action测试:只有TitleEditor-filter-1符合要求。

Data测试:同样可以推断出类型,
即"vnd.android.cursor.item/vnd.google.note",因而上面的
TitleEditor-filter-1最终通过测试。

类型推断

在前一节中,我们提到当Intent中只包含URI时,是有可能推断出
Type的。那么这个过程是在什么时候做的,为什么NotePad中的
“content://com.google.provider.NotePad/notes”最终可以得出
Type=“vnd.android.cursor.dir/vnd.google.note”?

实际上对Type的推断在startActivity起始就执行了,具体而言是
在execStartActivity中。

/*frameworks/base/core/java/android/content/Intent.java*/
public String resolveTypeIfNeeded(ContentResolver resolver)
{
if (mComponent != null) {
return mType; /*如果已经指定了Component Name,那就没必要
再解析类型了*/
}return resolveType(resolver);
}

resolveTypeIfNeeded——通过函数
名也可以看出,它负责从Intent中解析出相应的类型。

函数resolveTypeIfNeeded先判断ComponentName是否为空,是就
直接返回结果,否则继续调用如下方法:

public String resolveType(ContentResolver resolver) {if (mType != null) {return mType; //已经指定了类型,当然不需要再从URI中推断了}if (mData != null) {if ("content".equals(mData.getScheme())) {/*URI中的scheme必须是content才能
推断出类型。言下之意,像“http”这种网络协议是没有办法推测的*/return resolver.getType(mData); /*利用ContentResolver来解析*/}}return null;
}

由此可见,最终的类型推断是由ContentResolver来完成的。即:

public final String getType(Uri url) {IContentProvider provider =acquireExistingProvider(url); /*需要找到一个ContentProvider来完成解析。这给了我们一个提
示,getType有可能是每个Provider自己来完成的,而不是系统统一处理的*/if (provider != null) {//provider存在,直接由它完成解析try {return provider.getType(url);} catch (RemoteException e) {//异常处理}}if (!SCHEME_CONTENT.equals(url.getScheme())) {//又判断了一次是否为“content”return null;}try {String type = ActivityManagerNative.getDefault().getProviderMimeType(url);return type;}}

如果已经有现成的Provider,那么直接由它来解析类型;如果没
有可用的Provider,那么就要先动用AMS来找到相对应的Provider。这
和startActivity中利用Intent来找到Activity类似——这里是通过
URI来匹配Content Provider。因为Intent中的URI是“content://com.google.provider. NotePad/notes”,Authority是
com.google.provider.NotePad,所以最终会匹配到NotePad这个
Provider。

所以getType的核心步骤有两个。
(1)根据URI在AMS中找到对应的Content Provider,在这个例子中也就是NotePadProvider。
(2)根据provider中的getType()函数来解析类型。

因而可以肯定的是,每个provider都必须实现getType()方法;并且这
个接口还应该是抽象的,验证如下:

public abstract class ContentProvider implements
ComponentCallbacks2 {
…
public abstract String getType(Uri uri); //确实是抽象接口
…
}

最后来看看NotePadProvider是如何解析类型的。

@Overridepublic String getType(Uri uri) {switch (sUriMatcher.match(uri)) {case NOTES:case LIVE_FOLDER_NOTES:return NotePad.Notes.CONTENT_TYPE;case NOTE_ID:return NotePad.Notes.CONTENT_ITEM_TYPE;default:throw new IllegalArgumentException("Unknown URI "+ uri);}}

UriMatcher一共添加了3种模式,
当uri="content://com.google.provider.NotePad/notes"时,匹配的类
型是CONTENT_TYPE =“vnd.android.cursor.dir/vnd.google.note”。

根据之前对MIME类型的讲解,vnd表示用户自定义的类型。

当uri="content://com.google.provider.NotePad/notes/ID"时,匹配
的类型是:CONTENT_ITEM_TYPE=“vnd.android.cursor.item/vnd.google.note”。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com