Android:Intent全面解析

好像就是一天之间,比特币勒索病毒突然爆发了,是通过NSA泄漏的“永恒之蓝”黑客武器传播的,可远程攻击Windows的445端口(文件共享),如果系统没有安装今年3月的微软补丁,无需用户任何操作,只要开机上网,“永恒之蓝”就能在电脑里执行任意代码,植入勒索病毒等恶意程序。
吓得我赶紧对电脑里面重要的东西进行了备份,也建议大家养成良好的上网习惯,重要的东西及时备份。
恩,今天就分享一些Android基础知识。其实没有什么比官方文档更适合学习,但是官网的访问速度慢啊(大家都懂的)!恰巧看见了 刘明渊 的关于Intent的官方译文。写的很详细,特此保存,留作备忘。刘明渊的博客地址:http://blog.csdn.net/vanpersie_9987

Android应用框架鼓励开发者在开发应用时重用组件,本文将阐述如何用组件构建应用程序以及如何用intent将组件联系起来。如需阅读官方原文,请您访问链接:https://developer.android.com/guide/components/index.html

Intent 与 Intent Filters(Intents and Intent Filters)

Intent是一个传递消息的对象,您可以为Intent指定action来启动其他应用组件,Intent使组件之间通信更加便利,并且通信方式有很多,这里列举了主要的三点:

* 启动Activity:

您可以将intent作为参数调用startActivity()方法启动一个activity。该intent描述了将要启动的目标activity的特性并携带必要的数据信息。您还可以调用startActivityForResult()方法回传信息。

* 启动Service:

Service用于在后台执行任务,不与用户交互。您可以使用startService()方法执行一次性的操作(比如后在台下载一个文件),这需要Intent参数。 如果组件之间需要向CS结构一样通讯,您可以把Service想成一端,并调用bindService(),这同样需要Intent参数。

* 传递一个broadcast:

broadcast是一种可以被任何应用程序截获的广播机制。系统会基于当前发生的事件发出各式broadcast(比如设备开机时、开始充电时等),您可以调用sendBroadcast()、sendOrderedBroadcast()、 sendStickyBroadcast()方法发送一条广播,这需要传入Intent参数。

Intent的种类(Intent Types)

* 显式Intent:

通过指定具体类名启动一个组件。显式Intent一般用于同一应用程序内,因为您可以确定地知道要启动的组件名。另外,Android 5.0以后规定必须显式启动Service。

* 隐式Intent:

当希望启动具备某种特性的组件时,可以使用隐式Intent,隐式Intent无需指定类名,通常用于启动其他应用程序的组件,比如您打算启动一个地图定位的activity。

当您隐式地启动一个service或activity时,Intent会根据其中的内容,匹配其他组件中manifest文件的Intent-filter,启动符合条件的组件,并把Intent中的参数传过去,如果有多个intent-filter满足条件,那么系统会弹出一个对话框,由用户决定启动哪个组件。下面是intent与intent-filters配合启动组件的示意图:

见上图:
1、首先Activity A利用传入的Intent调用startActivity();

2、系统会根据该Intent的条件搜索Android系统中所有匹配的组件;

3、若找到了匹配intent的intent-filters所属的组件(Activity B),则启动该组件,并回调onCreate()方法,同时将Intent传递过去。

intent-filters是manifest文件中组件内部的一个标签,该标签描述了组件具备什么特性,如果您未配置intent-filters,那个该组件只能被显式启动。

创建Intent对象(Building an Intent)

Intent中包含了目标组件需满足的特性。Intent中应包含以下信息:

* Component name:

目标组件的名字。对于显式启动,这是不可缺省的,您可以使用Intent的构造方法传入组件名称,也可以调用setComponent(), setClass(), setClassName()这些方法传入组件名;若是隐式启动,这是可选的,但intent应包含其他信息(action、category、data);

* Action:

是一个可以指明目标组件行为的字符串。action很大程度上决定了category和data中应传入的信息;您也可以在自己的应用程序组件中指定action,以便让其他应用程序启动自己的组件。对应action中字符串,不建议使用硬编码的形式,而应在所属组件的类中设置为常量。

常见的action有:

ACTION_VIEW:用ACTION _VIEW启动的activity一般可以向用户展示一些信息,比如启动一个相册APP中展示图片的activity,或是启动一个地图APP中展示地址信息的activity。

ACTION_SEND:一般需要向通过ACTION _SEND启动的activity 附带着发送一些信息,这些信息由由目标activity决定该发送给谁,比如社交类APP或是发送邮件的APP。

您可以将action作为参数传入Intent的构造方法或setAction()方法中。

如需定义在自己的组件中定义action,应以应用的包名作为前缀,比如:
staticfinalStringACTION_TIMETRAVEL=”com.example.action.TIMETRAVEL”;

* Data:

一个URI对象是一个引用的data的表现形式,或是data的MIME类型;data的类型由Intent的action决定,比如说若action是ACTION_EDIT,那么data的URI应指向一个可编辑的文件。

当创建一个Intent时,除了为data指定URI以外,还应该指定data的MIME类型,比如说,一个用于展示图片的activity是不能用来放音乐的,如果您要启动这个activity,就需要将data的MIME类型指定为”image/png”、”image/jpeg”等。有些时候,从data的URI中就能推断出MIME的类型,比如当一个URI的schema是”content://”时,表明该URI指向了设备内部的一个文件并由ContentProvider管理着,系统可以根据该文件推断出data的MIME类型。

您可以调用setData()方法设置URI,调用setType()方法设置MIME类型,或调用setDataAndType()方法同时设置URI和MIME类型。

请注意:如果您需要同时设置URI和MIME类型,只能调用setDataAndType()方法,而不能分别调用setData()和setType(),因为调用setData()时会首先将setType()中的内容置空,反之亦然( they each nullify the value of the other)

* Category:

是一个字符串,表示目标组件的附加信息,大部分intent不需要category。以下是依稀而常用的category:

CATEGORY_BROWSABLE:表示目标activity可以被网页上的某个链接启动,如图片activity或e-mail信息activity。

CATEGORY_LAUNCHER:目标activity是任务栈的第一个activity,也就是应用程序的启示activity。

您可以将category参数传入addCategory()方法中。

上述的参数(component name, action, data, and category)代表了intent的属性,通过这些参数,系统可以筛选出符合条件的目标组件。除此之外,intent还可以包含下列参数,与上面的参数不同的是,系统不会使用这些参数来筛选目标组件:

* Extras:

一些intent可以携带的附加信息,以键值对的形式存储。可以使用putExtra()方法将键值对信息传入,也可以将键值对信息放在Bundle对象中,再通过将Bundle对象传入putExtra()中。

Intent类中封装了许多 ” EXTRA_* “形式的标准extra,如果想封装自己的extra键,请您以应用程序的报名作为前缀,比如:
staticfinalStringEXTRA_GIGAWATTS=”com.example.EXTRA_GIGAWATTS”;

* Flags:

该参数可以为intent添加元数据(meta-data),flag可以指导系统以何种方式启动一个activity、是否将启动的activity放在该应用的任务栈中,等等。

隐式Intent的例子(Example implicit intent)

请注意:若系统中没有满足隐式Intent的目标组件,则应用将崩溃(crash),所以首先应判断,再调用startActivity()。

以下是一个通过隐式intent启动一个“发送信息的Activity”的例子:

// Create the text message with a string
Intent sendIntent =newIntent(); 
sendIntent.setAction(Intent.ACTION_SEND); sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage); sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) !=null) {    startActivity(sendIntent); }

如果有一个目标组件满足intent,则启动该组件;若有多个满足intent的目标组件,则系统弹出一个列表以供选择。

使用应用选择器(Forcing an app chooser)

正如向上面说,系统中可能存在多个目标组件满足隐式intent,这时会弹出一个列表供用户选择,有些时候,用户希望每次都启动一个相同的组件(比如用户每次都想启动chrome浏览器而不是系统自带的浏览器),这时只需要勾选“不再询问”选项就行了,下次再启动时,列表将不再弹出;还有些时候,用户每次都需要对列表中的Activity进行筛选,比如启动用于分享的Activity,用户希望每次分享到不同的平台,这时需要调用Intent.createChooser()方法以保证每次都弹出选择列表,如下所示:


Intent sendIntent =newIntent(Intent.ACTION_SEND);
...
// Always use string resources for UI text.
// This says something like "Share this photo with"
String title = getResources().getString(R.string.chooser_title);
// Create intent to show the chooser dialog
Intent chooser =Intent.createChooser(sendIntent, title);

// Verify the original intent will resolve to at least one activity
if (sendIntent.resolveActivity(getPackageManager()) !=null) {    startActivity(chooser); }

接收隐式Intent(Receiving an Implicit Intent)

通过在manifest文件中配置intent-filter标签中的action, data, and category,可以设置筛选信息,只有同时符合上述三个标签设置的筛选信息,Intent才能开启您的应用程序组件:

* action标签:

可匹配Intent中的action参数。

* data标签:

可匹配Intent中的data参数(URI地址以及MIME 类型)。

* category标签:

可匹配Intent中的category 参数。
请注意:如组件需要被隐式启动,必须配置CATEGORY_DEFAULT

如想隐式启动一个分享的Activity,则目标Activity如下配置:

<activity android:name="ShareActivity">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

一个intent-filter中可以包含多个 action, data, category 标签。

若组件仅希望通过本应用启动,可将组件中的exported属性设为false。
请注意:为了避免隐式intent匹配上了您的Service组件,请不要在service中配置intent-filter(Service必须显式启动)

intent-filter举例(Example filters)

下面是一个社交APP的manifest文件示例:


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

</activity>

<activity android:name="ShareActivity">
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
        <action android:name="android.intent.action.SEND"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:mimeType="image/*"/>
    </intent-filter>
</activity>

action为 “android.intent.action.MAIN”表示该Activity是应用的主入口,且无需配置data。

category为 “android.intent.category.LAUNCHER”表示该activity的启动图标(通过icon属性配置)应添加到系统的launcher中,若未配置icon,则会使用application标签下的icon。
以上两个属性应成对出现。

如需隐式启动ShareActivity,仅需匹配一个intent-filter就行了。

使用Pending Intent(Using a Pending Intent)

PendingIntent是一个包装Intent的类,主要用于实现Intent的延时启动,PendingIntent的主要使用场合:

* 包装一个Notification的启动Intent;

* 包装一个App Widget的Intent(按Home键启动的activity);

* 包装一个延时启动的activity(如AlarmManager)。

使用PendingIntent启动的activity无需使用startActivity()就能启动,您应当使用对应组件的方法启动相应组件:

* 通过PendingIntent.getActivity()启动一个activity;

* 通过PendingIntent.getService()启动一个Service;

* 通过PendingIntent.getBroadcast()启动一个BroadcastReceiver;

解析Intent(Intent Resolution)

目标组件通过以下三点匹配相应的Intent:

* The intent action;

* The intent data (both URI and data type);

* The intent category。



* 匹配Action(Action test)

intent filter可定义零到多个action标签:

<intent-filter>
    <action android:name="android.intent.action.EDIT"/>
        <action android:name="android.intent.action.VIEW"/>  
    ...
</intent-filter>

intent需要匹配上其中一个action标签。如果intent-filter中没有action标签,则intent无需action就能匹配。

* 匹配Category(Category test)

intent filter可定义零到多个category标签:

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

intent中的定义的每一个category都需要匹配上intent-filter中的category标签,反之不成立(intent-filter中的category标签可能比intent中的定义的category多)。所以无论intent-filter中是否定义了category标签,未添加category的intent总能匹配上该intent-filter。
请注意:通过startActivity()或startActivityForResult()方法隐式启动的intent中,将自动被添加一个CATEGORY_DEFAULT的category,所以若您希望自己的activity能够被隐式启动,则需要在intent-filter中添加一个android.intent.category.DEFAULT的category标签。

* 匹配Data(Data test)

intent filter可定义零到多个data标签:

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

每个data标签都能设置mimeType和URI 结构,其中URI可分成四部分:scheme, host, port 和 path;其结构如下:
://:/
比如:

content://com.example.project:200/folder/subfolder/etc

其中:

* scheme为content;

* host为com.example.project;

* port为200;

* path为folder/subfolder/etc。

每一部分在data标签中都不是必须定义的,但存在一个线性依赖:

* 若scheme 未指定,则host被忽略;

* 若host未指定,则port被忽略;

* 若scheme和host均未指定,则path被忽略;

在intent中添加的data只需要匹配一部分intent-filter中的data(URI匹配):

* 若filter只定义了scheme,则intent的data定义的URI中只要包含了相同的scheme,就能匹配;

* 若filter只定义了scheme和host,则intent的data定义的URI中只要包含了相同的scheme和host,就能匹配;

* 若filter只定义了scheme、host和port,则intent的data定义的URI中只要包含了相同的scheme、host和port,就能匹配;

intent-filter匹配intent的data中URI和mimeType类型的规则如下:

  1. 如果intent-filter中未指定data,则未添加data的intent可以匹配;
  2. 如果intent-filter中指定了URI,但未指定mimeType,则按照上一段的规则匹配(intent中也应未指定mimeType);
  3. 如果intent-filter中指定了mimeType,而未指定URI,则可以匹配intent中指定了相同mimeType,而未指定URI的组件;
  4. 如果intent-filter中同时指定了mimeType和URI,则:

    • intent中添加的mimeType只要能匹配上intent-filter中的某一个mimeType,就能匹配上mimeType部分;

    • intent中添加的URI则按照上一段中的URI匹配规则,就能该匹配上URI部分;特别地:若intent中的URI的scheme 指定为content: 或者 file:,那么即便intent-filter中未定义URI,也能匹配成功。换句话说:包含content: 或者 file: 的URI总是能匹配上只定义了mimeType的intent-filter

  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值