您的位置:首页 > 移动开发 > Android开发

[Android开发向导]Intents and Intent Filters

2014-07-05 19:36 507 查看
Intent是用来请求其它组件的动作的消息对象,Intent方便了组件之间的通信,这里有三项基本用法:

启动一个activity:
你可以传入一个Intent参数来调用startActivity()。这个Intent记录着要被启动的activity和一些必要的数据。

如果当activity被finish时想要接收它的结果,调用startActivityForResult()。包含结果的Intent对象在要接收activity的onActivityResult()回调方法中[译者的话:重写onActivityResult()方法,第三个参数就是包含结果的Intent]

启动一个service:
你可以传入一个Intent参数来调用startService()开始一个实时操作(比如下载文件)。这个Intent记录着要被启动的service和一些必要的数据。

如果你用客户端-服务端接口设计,你可以传入Intent通过bindService()来绑定其他组件。

发送一个broadcast:
你可以传入Intent通过sendBroadcast()、sendOrderedBroadcast()、sendStickyBroadcast()来向其它应用发送broadcast

Intent 类型

Explicit intents [明确的意图]
特定的组件是通过名字(类的全名)来启动的。你通常可以使用明确Intent来启动你自己应用的组件,因为你知道你想启动的activity或者service的类名。

Implicit intents [不明确的意图]
不知道特定组件的名字时,我们可以通过指定action来查找。例如,你想让用户显示在地图上显示位置,你可以使用不明确的Intent来请求能够显示位置的应用

当你创建一个Explicit intent 时来启动activity或者service是,系统将立即启动在Intent对象里面指定的组件

当创建一个Implicit intents是,系统将在设备中其它应用的manifest文件中找Intent filter来和Intent对象里面的做比较,如果匹配就启动。如果从存在多个匹配的,会弹出一个对话框来让用户选择。

intent filter 是manifest文件里的一种标记,用来指示可以接收到Intent的类型。例如,你可以指定intent filter让其它组件来启动,你不指定任何intent filter,意味着你只能用过Explicit intent来启动

注意:为了确保应用的安全,通常我们可以只使用Explicit intent来启动service,不指定任何intent filter。使用intent filter存在安全隐患,因为你不能确保service怎样来回应这个Intent,而且用户也看不到哪个service启动了。



上图显示了一个Activity通过Implicit intent来启动另外一个Activity

创建一个Intent

一个Intent对象携带了系统用来判断哪个组件应该启动的信息,附加的信息为了接收组件能正确处理action
下面是Intent包含的主要信息

Component name [组件名字]
要启动组件的名字。携带了这个信息,表示这是Explicit intent,没有它就表示是Implicit intent

注意:当你启动时server时,你应该设置Component name,否则你不能确保service怎样来回应这个Intent,而且用户也看不到哪个service启动了。

Action [动作]
一个字符串用来指定执行特定的操作

在broadcast Intent中,发生和被报告的action和大程度上取决于其余Intent的结构-特别是data和extras

你可以为应用定义用户自己的action,但是通常还是使用intent类或者其它framework类定义的action常量,这里有一些公共的action来启动activity

ACTION_VIEW 当你有一些信息要用其它应用来展示给用户时,例如用图集应用来展示图片或者用地图应用来显示位置,你可以使用包含这个action的Intent来startActivity()

ACTION_SEND 又名分享Intent,当你有一些数据需要通过其它应用来分享时,例如邮件应用或者社交应用,你可以使用包含这个action的Intent来startActivity()

去查看下Intent类下定义的通用action常量,其它的action定义在framework的其它地方,例如打开系统设置的action定义在Setting中

你可以通过Intent的setAction()或者构造器来指定action

如果要定义你自己的action保证用了你的包名做前缀。例如:

static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";


Data [数据]
Data应该包含这URI引用和数据的MIME类型。数据的类型通常是用action决定的。例如 ACTION_EDIT的数据应该包含着被编辑的文档的URI。

当你创建一个Intent是,处理指定它数据的URI之外,数据类型(MIME类型)通常也是很重要的。一个activity可以显示图片但是也许不能播放音频,而这两种资源的URI是类似的。所以指定数据的MIME类型帮助系统找到接收你Intent的最好的组件。然而,MIME类型有时可以通过URI推测出来-当数据是content: URI,表明这个数据在设备上并且被ContentProvider控制。

使用setData()设置URI,使用setType()设置MIME类型,必要时可以同时设置setDataAndType()

注意:当你要同时设置URI和MIME类型时,用setDataAndType()。单独设置会使另外的值作废。

Category [分类]
一个字符串包含这个Intent应该被何种组件处理的附加信息,任何数字都可以用来描述Category,但是大部分Intent不需要Category。

这里有一些的Category:

CATEGORY_BROWSABLE 它的目标activity运行开启网页浏览器来显示链接数据-例如图片或者邮件消息

CATEGORY_LAUNCHER 这是一个任务的主activity,并且会被系统launcher列入

你可以通过addCategory()来指定Category

Extras [附加信息]
以键值对来携带请求action完成所需要的额外信息。有些action需要用到一些额外的准确信息

我们可以通过putExtra()来添加数据,也可以创建Bundle对象然后通过putExtras()来添加到Intent里

Intent类下定义了大量EXTRA_* 常量来使用。如果要定义你自己的action保证用了你的包名做前缀。例如:

static final String EXTRA_GIGAWATTS = "com.example.EXTRA_GIGAWATTS";


Flags [标识]
Flags用来作为Intent的元数据。这些标志可以指示系统如何launch一个activity(例如:该任务的活动应该属于哪个)launched后如何处理它(例如:它是否属于最近活动)

implicit intent示例

注意:用户也许没有安装能够处理我们Intent的应用,这样会造成奔溃。为了确保有activity接收,我们也调用Intent对象的resolveActivity()。如果结果非空,表示至少有一个应用可以处理我们Intent。这样我们就可以安全调用startActivity()了。
// 创建 text message字符串
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType(HTTP.PLAIN_TEXT_TYPE); // "text/plain" MIME 类型

// 查找是否有activity可以处理我们Intent
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}

强制选择打开方式

Intent intent = new Intent(Intent.ACTION_SEND);
...
String title = getResources().getString(R.string.chooser_title);

Intent chooser = Intent.createChooser(intent, title);

if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(chooser);
}
这样每次打开之前都要选择打开方式。不设置时,有时用户会选择记住某个打开方式,也行会造成麻烦。

接收Implicit Intent

注意:为了能够接收Implicit Intent,我们必须要设置Category为CATEGORY_DEFAULT。startActivity()和startActivityForResult()发送的都是CATEGORY_DEFAULT。如果你不定义这个Category你讲接收不到Implicit Intent。

注意:为了避免无意中调用了其它应用的Service,通常我们用explicit intent ,所以我们不定义Intent filter

注意:对于所以的activity我们必须定义在manifest文件中定义Intent filter来接受Implicit Intent。但是对于broadcast receiver我们可以通过registerReceiver()、unregisterReceiver()动态注册。这样你应用运行时可以在特定的时间监听特定的broadcast

注意:就算你不设置Intent filter,也不能保证其它应用访问你的组件。因为我们可以通过explicit intent 来访问。为此我们可以把exported 属性设置成false

filter示例

<activity android:name="MainActivity">
<!-- 应用主入口activity -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<activity android:name="ShareActivity">
<!-- 这个activity处理带文本数据的"SEND"action -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- 这个activity也处理带多媒体数据的"SEND"和"SEND_MULTIPLE" action -->
<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>
</activity>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: