Intent Intent 是一个消息传递对象。它是 Android 程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。
关键词: 指明要执行的动作 ,传递数据
Intent 的基本使用场景
启动 Activity : Activity 表示应用中的一个屏幕。通过将 Intent 传递给 startActivity()
,您可以启动新的 Activity 实例。Intent 描述了要启动的 Activity,并携带了任何必要的数据。
如果希望在 Activity 完成后收到结果,请调用 startActivityForResult()
。在 Activity 的 onActivityResult()
回调中,您的 Activity 将结果作为单独的 Intent 对象接收。
启动服务 : Service 是一个不使用用户界面而在后台执行操作的组件。通过将 Intent 传递给 startService()
,您可以启动服务执行一次性操作(例如,下载文件)。Intent 描述了要启动的服务,并携带了任何必要的数据。
如果服务旨在使用客户端-服务器接口,则通过将 Intent 传递给 bindService()
,您可以从其他组件绑定到此服务。
传递广播 : 广播是任何应用均可接收的消息。系统将针对系统事件(例如:系统启动或设备开始充电时)传递各种广播。通过将 Intent 传递给 sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast(),您可以将广播传递给其他应用。
参阅:官方文档 - Intent 和 Intent 过滤器
使用显式Intent 显式 Intent 指的是明确地按名称(完全限定类名)指定要启动的组件。比如说,如果我们想在FirstActivity这个活动中打开SecondActivity,我们可以在FirstActivity中的一个按钮点击中调用StartActivity
,传入intent对象。
1 2 3 4 5 6 7 8 Button buttonIntent = (Button) findViewById(R.id.button_intent);buttonIntent.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View view) { Intent intent = new Intent (MainActivity.this ,SecondActivity.class); startActivity(intent); } });
定义一个按钮
在按钮点击事件中 new 一个 intent 对象
调用 startActivity
,传入 intent 对象
使用隐式Intent 隐式 Intent 不会指定特定的组件,而是声明要执行的常规操作,从而允许其他应用中的组件来处理它。 例如,如需在地图上向用户显示位置,则可以使用隐式 Intent,请求另一具有此功能的应用在地图上显示指定的位置。
创建隐式 Intent 时,Android 系统通过将 Intent 的内容与在设备上其他应用的清单文件中声明的 Intent 过滤器进行比较,从而找到要启动的相应组件。 如果 Intent 与 Intent 过滤器匹配,则系统将启动该组件,并向其传递 Intent 对象。 如果多个 Intent 过滤器兼容,则系统会显示一个对话框,支持用户选取要使用的应用。
在AndroidManifest.xml中,把SecondActivity段修改如下
1 2 3 4 5 6 7 <activity android:name =".SecondActivity" > <intent-filter > <action android:name ="com.jerrysheh.hello.ACTION_START" /> <category android:name ="android.intent.category.DEFAULT" /> <category android:name ="com.jerrysheh.hello.MY_CATEGORY" /> </intent-filter > </activity >
在<intent-filter>中增添了action
和category
段,只有 action 和 category 同时匹配才能响应该Intent。每个Intent中只能指定一个action,但能指定多个category。
action :声明接受的 Intent 操作。
category :声明接受的 Intent 类别。
除了action
和category
外,还有一个data
,请参考官方文档
修改按钮点击事件, new Intent对象,因为我们想启动能到响应为com.jerrysheh.hello.ACTION_START
这个action的活动,因此参数填入com.jerrysheh.hello.ACTION_START
。
1 2 3 4 5 6 7 8 9 Button buttonIntent = (Button) findViewById(R.id.button_intent);buttonIntent.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View view) { Intent intent = new Intent ("com.jerrysheh.hello.ACTION_START" ); intent.addCategory("com.jerrysheh.hello.MY_CATEGORY" ); startActivity(intent); } });
或者,可以这样写,利用intent.setAction
方法。
1 2 3 4 5 6 7 8 9 10 Button buttonIntent = (Button) findViewById(R.id.button_intent);buttonIntent.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View view) { Intent intent = new Intent (); intent.setAction("com.jerrysheh.hello.ACTION_START" ); intent.addCategory("com.jerrysheh.hello.MY_CATEGORY" ); startActivity(intent); } });
如果intent.addCategory指定的Category没有一个活动能够匹配,那么程序会抛出异常。稍作修改,用resolveActivity()
方法来判断是否有应用能响应。假设没有活动匹配,就不启动startActivity()
;
1 2 3 4 5 6 7 8 9 10 11 12 13 Button buttonIntent = (Button) findViewById(R.id.button_intent);buttonIntent.setOnClickListener(new View .OnClickListener() { @Override public void onClick (View view) { Intent intent = new Intent ("com.jerrysheh.hello.ACTION_START" ); intent.addCategory("com.jerrysheh.hello.MY_CATEGORY" ); if (intent.resolveActivity(getPackageManager()) != null ) { startActivity(intent); } } });
Intent的更多用法 调用浏览器和拨号 new 一个 Intnet 对象后, 用 intent.setData(uri)
方法可以调用其他程序
比如调用浏览器打开 github
1 2 3 Intent intent = new Intent ("com.jerrysheh.hello.ACTION_START" );intent.setData(Uri.parse("https://www.github.com" )); startActivity(intent);
调用系统拨号拨打10010
1 2 3 Intent intent = new Intent (Intent.ACTION_DIAL);intent.setData(Uri.parse("tel:10010" )); startActivity(intent);
可以在 AndroidManifest 的 <intent - filter>标签中配置 标签, 指定当前活动可以响应什么类型的数据。这样其他app响应这种数据的时候,Android系统会弹出选项,你的app会在可选列表里面
1 2 3 4 5 6 7 8 <activity android:name =".SecondActivity" > <intent-filter > <action android:name ="com.jerrysheh.hello.ACTION_START" /> <category android:name ="android.intent.category.DEFAULT" /> <data android:schme ="https" /> <data android:host ="www.zhihu.com" /> </intent-filter > </activity >
这样, 你的app可以响应知乎网站的浏览器调用
使用Intent传递数据 向下一个活动传递数据 可以用 intent 的 putExtra 方法向下一个活动传递数据。核心思想是,把数据存在String里,通过intent参数传递给下一个活动,下一个活动启动后从intent取出。
存放 (MainActivity.java)
1 2 3 4 String data = "this is data" Intent intent = new Intent ("com.jerrysheh.hello.ACTION_START" );intent.putExtra(Intent.EXTRA_TEXT, data); startActivity(intent);
取出 (SecondActivity.java)
1 2 Intent intent = getIntent();String data = intent.getStringExtra(Intent.EXTRA_TEXT);
返回数据给上一个活动 Activity中有一个StartActivityForResult()
方法用于启动一个活动,但期望活动销毁后(通常是按下返回键或调用finish()
方法)返回一个结果给上一个活动。
MainActivity.java
1 2 Intent intent = new Intent (MainActivity.this ,SecondActivity.class);StartActivityForResult(intent, 1 );
SecondActivity.java
1 2 3 4 Intent intent = new Intent ();intent.putExtra("data_return" , "this is back data" ); setResult(RESULT_OK, intent); finish();
当然,返回数据后,会回调MainActivity的onActivityResult()
方法,因此我们还需要重写这个方法拿到SecondActivity返回来的数据。
1 2 3 4 5 6 7 8 9 10 11 @Override protected void onActivityResult (int requestCode, int resultCode, Intent data) { switch (requestCode) { case 1 : if (requestCode == RESULT_OK) { String returnData = data.getStringExtra("data_return" ); ... } break ; } }
使用 intent 传递对象 上面的 intent 只能传 String, 如果我们有一个 javabean 对象需要传递,怎么做呢?
首先将实体类(bean)实现 Serializable 接口。注意: 如果 bean 里面嵌套了 bean,内部类也要声明为实现 Serializable 接口。
1 2 3 4 5 6 7 8 9 public class bean implements Serializable { int a; int b; String c; Heybean d; public static class Heybean implements Serializable { ... } }
传递 activity
1 2 3 Intent intent = new Intent (context, DetailActivity.class);intent.putExtra("name" ,detailbean); context.startActivity(intent);
接收 activity
1 Bean detailBean = (Bean) getIntent().getSerializableExtra("name" );
Activity的生命周期 Android 用 任务(Task)来管理活动,一个Task就是一组存放在返回栈(Back Stack)里的活动的集合。系统总是会显示处于栈顶的活动给用户。
Activity的四种状态
运行状态
暂停状态(弹出式卡片,背景活动就是暂停状态)
停止状态
销毁状态
Activity的生存期
完整生存期 活动在onCraete()
和onDestroy()
之间经历的,就是一个完整生存期。
可见生存期 活动在onStart()
和onStop()
之间经历的,就是一个可见生存期。onStart()方法在活动从不可见变为可见时调用,onStop()反之。
前台生存期 活动在onResume()
和onPause()
之间经历的,就是一个前台生存期。onResume()方法在活动准备好和用户交互时调用。当系统准备去启动或恢复另一个活动时,onPause()将当前活动一些消耗CPU的资源释放,同时保存关键数据。
此外,还有一个onRestart()
,用于活动从停止状态变为运行状态之前调用,也就是活动被重新启动。
当系统内存不足时,用户按下back键返回到上一个Activity,有可能上一个Activity已经被系统回收,这时不会执行onRestart()
,而是执行onCreate()
。遇到这种情况,如果上一个Activity有数据,那这些数据都丢失了,这是很影响用户体验的。解决办法是调用onSaveInstantState()
回调方法。具体参见《第一行代码》第二版p62,以及Activity Google官方文档 (推荐)
Activity的启动模式 Activity有四种启动模式,可以在 AndroidManifest.xml 的 标签中修改
1 2 3 4 5 6 7 8 <activity android:name =".SecondActivity" android:launchMode ="singleTop" > <intent-filter > <action android:name ="com.jerrysheh.hello.ACTION_START" /> <category android:name ="android.intent.category.DEFAULT" /> </intent-filter > </activity >
android:launchMode
可填以下四种模式
标准模式,在MainActivity中启动MainActivity,会重复创建MainActivity的新实例。如创建了3个MainActivity的实例,需要按3次返回键才能完全退出。
无论MainActivity是否在栈顶,在整个应用程序上下文中只存在一个MainActivity实例。