Intent学习笔记
一、intent作用
intent是一个消息对象,用来启动app组件,其使用上主要分为三类:
1. 用于启动activity。建立Intent对象,将其作为参数传递到startActivity或StartActivityforResult()中来启动相应的activity。
2. 用于开启服务。将intent作为参数传递给startService或者bindService来开启服务.
3. 用于发送广播。将Intent作为参数传递给sendBroadcast(), sendOrderedBroadcast(),sendStickyBroadcast()来发送广播。
二、Intent
可以定义两种形式Intent:
1. 显式的Intent。通过这种方式,可以显示的指定要启动的Activity或Service,也就是说此时知道要启动的组件名称。
2. 隐式的Intent。通过这种方式,指定Intent的参数,action,data等,然后这些参数匹配组件的intentfliter来启动相应的组件。
需要说明的一点是,为了安全考虑,不要采用隐式的方式启动Service,因为你这样做,并不能确定会启动哪个Service;并且当你为自己的Service设置intentfliter后,其它app有可能启动该Service。从andriod 5.0(api 21)开始,当通过隐式的Intent传递给bindservice时,系统会抛出异常
下图展示了隐式Intent传递的流程
首先Activity A创建一个隐式Intent,并将其作为参数传递给StartActivity;andriod系统基于该Intent,匹配各Activity的intentfliter,找到匹配该Intent的Activity;然后通过调用该Activity的oncreate方法启动该Activity,并将Intent作为参数传递给onCreate。
有一点非常重要: 当采用隐式Intent来启动Activity时,可能没有找到可以匹配的Activity,此时app就会crash,所以在执行StartActivity之前通过Intent调用resolveActivity()来判断是否有可匹配的Activity。如果返回结果不为null,则至少存在一个可以启动的Activity。代码如下:
if (sendIntent.resolveActivity(getPackageManager()) != null) {
startActivity(sendIntent);
}
三、Intent中应该传递的内容
一个Intent对象应该包含系统用于判断启动哪个组件的信息 以及 组件启动后一些辅助信息。
Component name。
组件名称,该信息是一个可选项,包不包括该信息是决定Intent类型的关键:如果传递了组件名称,则为显示的Intent;否则为隐式的Intent。
可以通过Intent的构造函数、setComponent(), setClass(), setClassName()来设置该信息。
// 通过构造函数
Intent intent = new Intent(aActivity.this, bActivity.class);
startActivity(intent);
// 通过setComponent
Intent intent = new Intent();
intent.setComponent(new ComponentName(getApplicationContext(), bActivity.class));
startActivity(intent);
// 通过setClass来设置该信息
Intent intent = new Intent();
intent.setClass(aAvtivity.this, bActivity.class);
startActivity(intent);
// 通过setClassName来设置该信息
Intent intent = new Intent();
intent.setClassName(aAvtivity.this, bActivity.class.getName());
startActivity(intent);
Action。
启动组件完成的动作,在对应的Activity中的intentFliter中进行配置。可以用过setAction或者构造函数来制定Action参数。当设置自定义的action时,最好加上app的包名,如:
static final String ACTION_TIMETRAVEL = "com.example.action.TIMETRAVEL";
Data。
设置要启动组件要处理的数据,比如当设置Action为ACTION_EDIT时,就可以通过设置data来制定要编辑的文件。另外,当设置了data之后,可能需要设置数据类型,因为一个Activity能够处理图片但不一定能够处理视频。(但是一般可以通过设置的数据来推断出类型)。可以通过setData (接受一个uri对象)来单独设置数据,也可以通过setType来单独设置数据类型,还可以通过setDataAndType来设置数据和类型。
需要注意的是,当需要及设置数据又设置类型的时候,不要分别调用setData及setType函数,而是调用setDataAndType。
Category
分类。用来定义要启动的组件的分类,可以定义多个分类;其实大多数情况下这个参数是不要设定的。 设定分类的方法的是setCategory().
通过上述的几类信息,Android系统可以得到intent想要启动的组件。在上述基础上,Intent还可以携带一些附加信息
Extras
可以用过putExtra的各种重载方法来传递信息;同时也可以新建Bubble对象,在将该对象传递到putExtras中来传递信息。具体方法:
// 通过putExtra设置信息
Intent intent = new Intent(activity.this, bActivity.class);
intent.putExtra("valueKey", "nihao");
startActivity(intent);
// 在目的Activity中的onCreate中接收传递信息
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_b);
Intent intent = this.getIntent();
Log.e("tag", "b--" + intent.getStringExtra("valueKey"));
}
// 通过Bubble的方式来传递信息
Intent intent = new Intent(aActivity.this, cActivity.class);
Bundle bundle = new Bundle();
bundle.putString("valueKey", "你好");
intent.putExtras(bundle);
startActivity(intent);
// 在目的Activity获取信息
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_c);
Intent intent = this.getIntent();
Bundle bundle = intent.getExtras();
Log.e("tag", bundle.getString("valueKey"));
}
Flag
用来定义Activity该以何种方式启动,以及启动之后该如何处理该Activity。该参数通过setFlag来进行设置。
四、intentFliter
通过配置文件,设置Activity的intentFliter,可以起到过滤的作用,从而启动相应的Activity。
举例来说明如何配置:
<activity android:name="MainActivity">
<!-- This activity is the main entry, should appear in app launcher -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="ShareActivity">
<!-- This activity handles "SEND" actions with text data -->
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
<!-- This activity also handles "SEND" and "SEND_MULTIPLE" with media data -->
<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>
需要说明以下几点:
1. 一个activity可以有多个intent-fliter标签,形成action,category,data等不同的组合形式
2. 每个intent-fliter标签内可以有0个或多个action,category标签,可以有0个或多个data标签。如果某个Activity不属于任何一个category,则应该属于 CATEGORY_DEFAULT,即<category android:name="android.intent.category.DEFAULT"/>
3. 在MainActivity中设置action为ACTION_MAIN,则表示该Activity为app入口,并且不用为此Activity传入参数。设置CATEGORY_LAUNCHER 类别,则说明该Activity设置的icon应该作为app的icon;如果没有设置icon属性,则在 application标签中寻找该属性。这两个必须要设置在一起才能起作用
4. 对于所有的Activity来说,都要在配置文件中设置intent fliter。但是,对于broadcast来说,应该在执行registerReceiver方法时动态的注册filter属性,然后可以在registerReceiver取消注册。这样做允许你的app只在运行的特定一段时间内可以监听到这个广播。
5. 如果不想某个activity被其它app打开,可以设置它的属性exported为false,即:
<activity android:name=".aAvtivity"
android:exported="false">