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);
隐式的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; } } }
我们再看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); }
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: 打开浏览器, 可以指定搜索内容;