Android 中的 Intent 是将要执行的操作的一种抽象的描述,是一个用于Android 各个组件之间传递消息的对象。
Intent 的基本用法
Intent 基本的使用方法主要有三种:
启动一个新的 Activity 实例。
通过将 Intent 传入startActivity()
中可以启动一个新的实例,其中的 Intent 描述了要启动的 Activity,并包含了一些必要的数据启动一个服务
通过将 Intent 传入startService()
中可以启动一个服务器执行一些一次性的操作(如下载文件等)。其中的 Intent 描述了要启动的服务,并包含了一些必要的数据。发送广播
广播指那些所有应用都可以接受的消息,通过将 Intent 传递给sendBroadcast()、sendOrderedBroadcast() 或 sendStickyBroadcast()
,可以将广播传递给其他应用。
Intent 的类型
Intent 可以分为两种类型:
显式Intent(Explicit Intents)
通过完全限定类名来指定要启动的组件。当明确的知道要启动的 Activity或 Service 的名称时可以使用显式的 Intent。例如,启动一个 Activity 或 Service 去响应用户的操作。创建显式 Intent 启动 Activity 或 Service,系统会立即启动 Intent 指定的组件。隐式 Intent(Implicit Intents)
不指定特定的组件,而是声明要执行的操作,从而允许其它的组件来处理。例如发送一个 E-mail,则可以使用隐式的 Intent,允许其它的应用来处理该操作。
显式 Intent的使用
下面的代码表示,当点击按钮 Next
时,启动一个显式的 Intent,转向一个指定的页面
Button Next = (Button)findViewById(R.id.Next);
Next.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
Intent intent = new Intent(firstActivity.this,secondActivity.class);
startActivity(intent);
}
});
隐式 Intent 的使用
下面的代码,当点击按钮 Broswer
时,启动一个隐式的 Intent,打开一个 Web 页面
Broswer Next = (Button)findViewById(R.id.Broswer);
Next.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.Parse("http://www.baidu.com");
startActivity(intent);
}
});
创建隐式的 Intent时,Android 系统将 Intent 中指定的内容与设备上其它应用的 AndroidManifest.xml 中声明的 Intent-filter 进行比较,如果 Intent 与声明的 Intent-filter 匹配,则启动对应的组件,并将 Intent传递给它。如果存在多个 intent-filter匹配,则提供一个选择器供用户选择使用哪个应用来处理。
注意:显式的 Intent 总是能够传递给它的目标,而不管目标组件的 intent-filter 是如何定义的
用户可能没有任何应用可以处理你发送到 startActivity
的隐式 Intent,如果出现这种情况,则调用会失败,且 应用会崩溃 ,因此,在发出一个隐式的 Intent 之前最好验证一下当前设备是否具有可以处理该 Intent 请求的应用。可以调用 Intent 对象的 resolveActivity()
来验证,如果方法返回 null,则说明当前设备没有可以处理该 Intent 的应用,必要情况下应该停止发出此 Intent,如果 返回不为空,则表示至少存在一个可以处理该 Intent的应用。
注意:Android 官方建议,通过显式的 Intent 来启动服务,并且不要为服务声明 Intent-Filter,因为使用隐式的 Intent 启动服务时,无法确定响应 Intent* 的服务,用户也无法看到启动的服务,存在一定的安全隐患。在 Android 5.0 开始,使用隐式的 Intent 调用
bindService()
将会发生异常。
接收隐式的 Intent
要声明应用可以处理哪些隐式的 Intent,需要在 AndroidManifest.xml 中使用 intent-filter 属性为组件声明一个或多个 intent 过滤器,每个 intent 过滤器都可以根据 Intent 的操作、数据和类别指定自身接收的 Intent。仅当隐式的 Intent 匹配某一 Intent的规则时,Android 系统才会将 隐式的 Intent 传递给应用组件。如果一个组件没有声明任何的 Intent 过滤器,那么它只能通过显式Intent 的方式启动。
每个 Intent 过滤器均由 AndroidMainfest.xml 中的 intent-filter
属性标签来定义,并嵌套在响应的最近中(例如 Activity)
<Activity android:name=".second">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<catetory android:name="android.intent.category.DEFAULT"/>
<data android:scheme="http"/>
</intent-filter>
</Activity>
intent-filter 中可以使用的属性
action
在 name 属性中,声明接受的 Intent 操作。该值必须是操作的文本字符串值,而不是类常量。data
使用一个或多个指定数据 URI 各个方面(scheme、host、port、path 等)和 MIME 类型的属性,声明接受的数据类型。data 标签内的 scheme等几个属性均为可选,但存在线性依赖关系,具体如下:
1. 如果未指定 scheme 则忽略 host
2. 如果未指定 host 则忽略 port
3. 如果未指定 scheme 和 host,则忽略 path
- category
在 name 属性中,声明接受的 Intent 类别。该值必须是操作的文本字符串值,而不是类常量。
在定义 intent-filter 时,我们可以使用上述属性中的一个或多个进行任意的组合,系统通过将
Intent 与 intent-filter 中定义的属性规则进行测试,只有通过所有的测试时,才会将 Intent 传递给该组件。
注意:使用 Intent 过滤器时,无法安全地防止其他应用启动组件。如果需要保证只有自己的应用可以访问应用内部的某些组件,可以针对该组件将其 exported
属性设置为 false
使用 Intent 在 Activity 间传递数据
使用 Intent 向下一个 Activity 传递数据
下面的例子,当我们点击 Next
按钮时,将输入框的值传入下一个 second 页面
Button btn = (Button)findViewById(R.id.Next);
final EditText UName = (EditText)findViewById(R.id.UName);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
Intent transferData = new Intent(MainActivity.this,second.class);
transferData.putExtra("data",UName.getText().toString());
startActivity(transferData);
}
});
在 second 页面中,我们可以通过以下的方式来获取传入的数据
Intent intent = getIntent();
String UName = intent.getStringExtra("data");
使用 Intent 回传数据给上一个 Activity
有时候我们希望启动一个新的 Activity 来处理一些数据,然后可以回传处理结果到当前的 Activity,这是我们便可以通过 Activity 的 startActivityForResult
来实现。
下面的例子,在第一个 Activity 中点击按钮时将文本框中的内容传入一个新的 Activity,在第二个 Activity 中对第一个 Activity 传过来的内容进行处理,然后回传给第一个 Activity。
第一个 Activity:
Button btn = (Button)findViewById(R.id.Click);
final EditText UName = (EditText)findViewById(R.id.UName);
btn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view){
Intent intent = new Intent(MainActivity.this,second.class);
intent.putExtra("data",UName.getText().toString());
startActivityForResult(intent,1);//第二个参数表示一个请求码,必须唯一
}
});
第二个 Activity
Button SayBtn = (Button)findViewById(R.id.Say);
SayBtn.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
String UName = getIntent().getStringExtra("data");
Intent intent = new Intent();
intent.putExtra("return_data","我明白了,你的名字为: " + UName + "很高兴认识你");
setResult(RESULT_OK,intent);
finish();
}
});
重写第一个 Activity 的 onActivityResult
方法,该方法会在第二个 Activity 销毁后调用
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch(requestCode){
case 1:{
if(resultCode == RESULT_OK){
String replyData = data.getStringExtra("return_data");
Toast.makeText(this,replyData,Toast.LENGTH_SHORT).show();
}
}
break;
}
}
在这里我们便可以接收到第二个 Activity 处理后的数据了。