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

Android开发之Intent

2016-04-08 11:55 549 查看
1.概述:Intent是一种消息传递机制,可以在应用程序内使用,也可以在应用程序间使用。

Intent可以用于:

1)使用类名显式启动一个Service或者Activity

2)启动一个Activity或者Service来执行一个动作的Intent,通常需要特定的数据,或者对特定的数据执行动作。

3)通过广播intent来公布某个系统事件

2.Intent用途

Intent最常见的用途是绑定应用程序组件,并在应用程序之间进行通信。Intent用来启动Activity,允许创建不同屏幕的一个工作流。

1)显示启动新的Activity

要显式的启动一个Activity,可以创建一个新的Intent来指定当前Activity的上下文以及要启动的Activity的类。然后把这个Intent传递给startActivity。

Intent intent = new Intent(this, OtherActivity.class);
startActivity(intent);


2)隐式启动新的Activity

隐式的Intent提供了一种机制,可以让匿名的应用程序组件响应动作请求。这就意味着可以要求系统启动一个可执行给定动作的Activity,而不必知道启动哪一个应用程序或者Activity。例如,如果我们想要调用系统拨号功能,除了可以实现一个新的拨号程序外,我们可以使用一个隐式的Intent来完成拨号功能。

Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + num));
startActivity(intent);


Android会解析上面这段代码中的Intent,并启动一个新的Activity,该Activity会提供对这个电话号码进行拨号的动作—在这个情况下,通常是Phone Dialer。其实隐式启动的本质就是根据需要启动的Activity的动作和策略deng启动目标Activity,也就是说Intent所携带的参数可以并且仅可以匹配系统中唯一的Activity或者Service(Android5.0已经不支持隐式启动Service)。

Tip:为什么之前可以隐式启动Service,到了Android5.0就不可以了?

我们看源码,Android4.4版本源码

private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (true || getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.KITKAT) {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
//IllegalArgumentException ex = new IllegalArgumentException(
//        "Service Intent must be explicit: " + service);
//Log.e(TAG, "This will become an error", ex);
//throw ex;
}
}
}


在Android 4.4的ContextImpl源码中,能看到如果启动service的intent的component和package都为空并且版本大于KITKAT的时候只是报出一个警报,告诉开发者隐式声明intent去启动Service是不安全的.但是我们可以看到下面有一段代码被注释掉了,注释掉的代码就是抛异常的代码,就是彻底不让这么干了。看来google早就想这么干了.

我们再看Android5.0的源码:

private void validateServiceIntent(Intent service) {
if (service.getComponent() == null && service.getPackage() == null) {
if (getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.LOLLIPOP) {
IllegalArgumentException ex = new IllegalArgumentException(
"Service Intent must be explicit: " + service);
throw ex;
} else {
Log.w(TAG, "Implicit intents with startService are not safe: " + service
+ " " + Debug.getCallers(2, 3));
}
}
}
在Android 5.0的源码中上面注释的代码已经不注释了,当targetSdkVersion版本大于LOLLIPOP直接异常抛出来,要求Service intent必须显式声明.所以如果开发的应用指定targetSdkVersion版本是小于LOLLIPOP的话还是按以前的方式给报个警报,这也就造成了如果没有做了完善的Android 5.0兼容就贸然把targetSdkVersion升到LOLLIPOP的话很有可能就会碰到这个问题.并且这个问题是很严重的,想象一下,你的app自升级的Service是隐式启动的,碰到这个问题后app就不能自升级了,这批用户有可能就一直停留在当前版本.会产生很致命的问题.

3.确定intent是否能解析

在自己的应用程序中启动第三方应用程序的Activity或者Service是十分方便的,但是,你无法确保用户设备上面是否安装了某个应用程序,或者设备上有能够处理的你的请求的应用程序。因此在调用startActivity之前,确定调用是否可以解析为一个Activity是一种很好的做法。通过调用Intent的resolveActivity方法传入包管理器,可以对包管理器进行查询,确定是否存在Activity能够启动以响应的Intent。

如:

Intent intent = new Intent();
intent.setAction(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:" + num));
PackageManager pm = getPackageManager();
ComponentName cn = intent.resolveActivity(pm);
if(cn == null){
//找不到系统中可启动的Activity
}else{
startActivity(intent);
}


4.从Activity返回结果

通过startActivity启动的Activity独立于其父Activity,并且在关闭时不会提供任何反馈信息。

当需要反馈时,可以启动一个Activity作为另一个Activity的子Activity,用它向父Activity传递结果。子Activity只是以一种不同的方式启动Activity。因此,必须在应用程序的manifest文件中注册它们,就像其他任何一个Activity一样。在manifest文件中注册任何Activity都可以作为子Activty打开,包括系统Activity或者第三方应用程序的Activity。当子Activity结束时,它会触发调用Activity内的时间处理程序onActivityResult。对于一个Activity为另一个Activity提供数据输入(比如用户从一个列表中选择某一项)的情况,子Activity特别适用。

启动子Activity

startActivityForResult的工作方式和startActivity相似,但是有一个重要的区别。除了传入显式或隐式Intent来决定启动哪个Activity以外,还需要传入一个请求码。这个值将用于唯一标识返回结果的子Activity。

如:显式启动

/**
* Explicitly starting a sub-Activity for a result
*/
private static final int SHOW_SUBACTIVITY = 1;

private void startSubActivity() {
Intent intent = new Intent(this, MyOtherActivity.class);
startActivityForResult(intent, SHOW_SUBACTIVITY);
}


隐式启动

/**
* Implicitly starting a sub-Activity for a result
*/
private static final int PICK_CONTACT_SUBACTIVITY = 2;

private void startSubActivityImplicitly() {
Uri uri = Uri.parse("content://contacts/people");
Intent intent = new Intent(Intent.ACTION_PICK, uri);
startActivityForResult(intent, PICK_CONTACT_SUBACTIVITY);
}


当准备好返回子Activity时,可以在调用finish之前调用setResult,以便向调用或者启动它的那个Activity返回一个结果。

setResult方法有两个参数:结果码和表示为Intent的结果数据本身。

结果码,是运行子Activity的结果——通常是Activity.RESULT_OK或者Activity.RESULT_CANCELED。在某些环境下,OK和CANCLED 不足以精确描述可用的返回结果时,可能希望使用自己的自定义响应码(response code)来处理应用程序特定的选择;setResult支持任意的整数值。

作为结果返回的intent通常包含某段内容(比如选择的联系人、电话号码或媒体文件)的URI和用于返回附加信息的一组extra。

实例:

final ListView listView = (ListView)findViewById(R.id.listView1);

/**
* Returning a result from a sub-Activity
*/
Button okButton = (Button) findViewById(R.id.ok_button);
okButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
long selected_horse_id = listView.getSelectedItemId();

Uri selectedHorse = Uri.parse("content://horses/" +
selected_horse_id);
Intent result = new Intent(Intent.ACTION_PICK, selectedHorse);

setResult(RESULT_OK, result);
finish();
}
});

Button cancelButton = (Button) findViewById(R.id.cancel_button);
cancelButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
setResult(RESULT_CANCELED);
finish();
}
});


如果用户通过按下返回键关闭Activity,或者在调用finish之前没有调用setResult,那么结果码将被设为RESULT_CANCELED,结果intent被设为null。

处理子Activity返回的结果

当一个子Activity关闭的时候,它会触发其调用他的Activity的onActivityResult事件处理程序。可以通过重写这个方法来处理从子Activity返回的结果。

onActivityResult接收多个参数:

请求码:在启动正在返回的子Activity时使用的请求码。

结果码:子Activity设置的结果码,用来说明其结果。它可以是任何整数值,但是一般情况下都是Activity.RESULT_OK或者Activity.RESULT_CANCELED。

数据:intent用来包装所有返回数据。返回的数据intent内以extra的形式返回信息。

代码事例:

/**
*  Implementing an On Activity Result handler
*/
private static final int SELECT_HORSE = 1;
private static final int SELECT_GUN = 2;

Uri selectedHorse = null;
Uri selectedGun = null;

@Override
public void onActivityResult(int requestCode,
int resultCode,
Intent data) {

super.onActivityResult(requestCode, resultCode, data);

switch(requestCode) {
case (SELECT_HORSE):
if (resultCode == Activity.RESULT_OK)
selectedHorse = data.getData();
break;

case (SELECT_GUN):
if (resultCode == Activity.RESULT_OK)
selectedGun = data.getData();
break;

default: break;
}
}


5.原生的Android动作

ACTION_ALL_APPS: 打开一个列出所有已安装程序的Activity;

ACTION_ANSWER: 打开一个处理来电的Activity,通常这个动作是由本地电话拨号程序处理;

ACTION_BUG_REPORT: 报告BUG;

ACTION_CALL: 打开一个电话拨号程序, 使用Intent的数据URI提供的号码拨打电话;

ACTION_CALL_BUTTON: 拨打按钮, 调用拨号程序;

ACTION_DELETE: 删除Intent中URI指定的数据;

ACTION_DIAL: 调用拨打电话的程序, 使用Intent的号码, 没有直接打出, 而ACTION_CALL直接拨打电话;

ACTION_EDIT: 可以编程Intent中URI提供的数据;

ACTION_INSERT: 在Intent的URI指定的游标中插入数据;

ACTION_PICK: 选择Intent中URI指定的Content Provider的某项;

ACTION_SEARCH: 搜索, 搜索词可以在Intent的extra中提供;

ACTION_SEARCH_LONG_PRESS: 硬件搜索键长按操作;

ACTION_SENDTO: Intent中的URI所指定的联系人发送短信;

ACTION_SEND: Intent中URI所指定的联系人, 发送信息(EMAIL, 彩信等);

ACTION_VIEW: 以合理的方式查看, Intent中URI的内容;

ACTION_WEB_SEARCH: 打开浏览器, 可以指定搜索内容;

除此之外,Android还有很多广播动作,它们用来创建广播intent以公布系统事件。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: