一、穿梭在活动中的Intent
Intent是Android程序中各组件之间进行交互的一种重要方式,它不仅可以指明当前组件想要执行的动作,还可以在不同组件之间传递数据。Intent一般可被用于启动活动、启动服务以及发送广播等场景。
1、显式Intent
Intent有多个构造函数的重载,Intent(ContextpackageContext,Class<?>cls)
是其中一个。这个构造函数接收两个参数,第一个参数Context
要求提供一个启动活动的上下文,第二个参数Class
则是指定想要启动的目标活动,通过这个构造函数就可以构建出Intent
的“意图”。
//得到一个intent对象
Intent intent = new Intent(getApplicationContext(), MainActivity2.class);
//运行intent对象的实例
startActivity(intent);
然后我们应该怎么使用这个Intent呢?Activity类中提供了一个startActivity()
方法,这个方法是专门用于启动活动的,它接收一个Intent参数,这里我们将构建好的intent
传入startActivity()
方法就可以启动目标活动了。
2、隐式Intent
2.1 启动内部activity
相比于显式Intent,隐式Intent则含蓄了许多,它并不明确指出我们想要启动哪那一个活动,而是指定了一系列更为抽象的action和category等信息,然后交由系统去分析这个Intent,并帮我们找出合适的活动去启动。
通过在标签下配置intent-filter:的内容,可以指定当前活动能够响应的action
和category
,打开AndroidManifest.xml,
添加如下代码:
使用intent的另一个构造函数,直接将action的字符串传进去。
Intent intent = new Intent("android.intent.action.Button2");
//运行intent对象的实例
startActivity(intent);
2.2 启动外部activiyty
使用隐式Intent,我们不仅可以启动自己程序内的活动,还可以启动其他程序的活动,这使得Android多个应用程序之间的功能共享成为了可能。比如说你的应用程序中需要展示一个网页,这时你没有必要自己去实现一个浏览器(事实上也不太可能),而是只需要调用系统的浏览器来打开这个网页就行了。
button.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 intent = new Intent(Intent.ACTION_VIEW,Uri.parse("tel:10086"));
* startActivity(intent);
*/
}
});
这里我们首先指定了Intent的action是Intent.ACTION VIEW,这是一个Android系统内置的动作,其常量值为android.intent.action.VIEW。然后通过Uri.parse()方法,将一个地址字符串解析成一个Uri对象,再调用Intent的setData()方法将这个Uri对象传递进去。
Intent.ACTION_VIEW
是一个常量,它是Android中的一个标准动作(Action),用于指定一个Intent的目标是查看某种数据。具体而言,它表示要查看(显示)指定的数据,比如网址、地图位置、图片、文档等。
与此对应,我们还可以在标签中再配置一个标签,用于更精确地指定当前活动能够响应什么类型的数据。标签中主要可以配置以下内容。
- android:scheme 用于指定数据的协议部分,如上例中的http部分。
- android:host 用于指定数据的主机名部分,如上例中的www.baidu.com部分。
- android:port 用于指定数据的端口部分,一般紧随在主机名之后。
- android:path 用于指定主机名和端口之后的部分,如一段网址中跟在域名之后的内容。
- android:mimeType 用于指定可以处理的数据类型,允许使用通配符的方式进行指定。
<activity
android:name=".ThirdActivity"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
</intent-filter>
</activity>
android.intent.category.DEFAULT
,表示这个Activity是一个默认的处理器,可以处理普通的View操作。
android.intent.category.BROWSABLE
,表示这个Activity支持浏览(Browsing)操作。
除了https协议外,我们还可以指定很多其他协议,比如geo表示显示地理位置、tel表示拨打电话。下面的代码展示了如何在我们的程序中调用系统拨号界面。
geo参数为经纬度,tel参数为电话号码
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("tel:10086"));
startActivity(intent);
}
});
3、向下一个活动传递数据
在启动活动时传递数据的思路很简单,Intent
中提供了一系列putExtra()
方法的重载,可以把我们想要传递的数据暂存在Intent
中,启动了另一个活动后,只需要把这些数据再从Intent
中取出就可以了
在上一个活动中设置信息如下:
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), ThirdActivity.class);
intent.putExtra("extra_data","Hello 世界");
startActivity(intent);
}
});
注意这里putExtra()方法接收两个参数,第一个参数是键(用于后一个活动取出数据),用于后面从Intent中取值,第二个参数才是真正要传递的数据。
在下一个活动中使用Intent获取数据
public class ThirdActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
Intent intent = getIntent(); //得到intent对象
String data = intent.getStringExtra("extra_data");
Log.d("TAG1", data);
}
}
通过putExtra()参数的键,获取数据。
4、向上一个活动传递数据
startActivityForResult 的替代方案registerForActivityResult
4.1 设计思路
大致思路:先向下传递一个Intent,向下的activity操作这个Intent后再次将这个Intent返回给上一个activity。
既然需要使用新的功能,那么我们就必须要先了解以下,刚说到的ActivityResultLauncher
、ActivityResultContract
、ActivityResultCallback
到底是些什么东西
- ActivityResultLauncher 从字面意思其实就能很好理解,可以理解它就是一个Activity的启动器,它的作用就是承载启动对象与返回对象,通
registerForActivityResult
返回该对象,这时并不会立即启动另一个Activity。 - ActivityResultContract 是用来协定所需的输入类型以及结果的输出类型,Android默认提供了一些常用的定义,例如上面所使用到到
ActivityResultContracts.StartActivityForResult()
。当然这里你也可以通过继承ActivityResultContract
实现自己的定义。 - ActivityResultCallback 通过名字就可以了解到这是启动Activity并返回到当前Activity时的结果回调。
4.2 设计ActivityResultLauncher
根据上面的流程图我们可以知道首先先实现ActivityResultLauncher
,java实现代码如下:
private ActivityResultLauncher<Intent> resultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
//判断是否传入正确的result
if(result.getResultCode() == RESULT_OK){
Intent intent = result.getData(); //获取上一个活动返回的Intent
//判断上一个活动的Intent是否存在,存在则在日志中输入
if(intent != null){
String str = intent.getStringExtra("data_return");
Log.d("DATA",str);
}
}
}
});
通过这段代码我们可以看到使用了registerForActivityResult
这个方法,传递了两个参数。
4.2.1 registerForActivityResult() 方法解析
registerForActivityResult() 方法接收两个参数。
第一个参数是一种 Contract 类型。
Contract 用于指定一个 Activity 被调用时,使用 I 类型的输入,产生 O 类型的输出。
第二个参数是回调。即当存在返回值时,处理返回结果的代码。用 lambda 表达式来实现
在实现一个 Activity 向上一个 Activity 传递数据的需求中第一个参数可以传入 ActivityResultContracts.StartActivityForResult()
该对象的 输入类型 I 为 Intent
,输出类型 O 为 ActivityResult
4.3 向下传递Intent
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainBinding activityMainBinding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(activityMainBinding.getRoot());
Button button = (Button) activityMainBinding.button1;
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(getApplicationContext(), SecondActivity.class);
//向下传递Intent
resultLauncher.launch(intent);
}
});
}
4.4 下一个活动接收Intent
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMain2Binding binding = ActivityMain2Binding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
View button = binding.button2;
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//获取前一个活动传递的Intent
Intent intent = getIntent();
//给这个Intent封装value
intent.putExtra("data_return","xupt3G");
//返回活动的结果
setResult(RESULT_OK,intent);
Toast.makeText(getApplicationContext(),"已经返回结果", Toast.LENGTH_SHORT).show();
finish();
}
});
}
setResult()方法接收两个参数,第一个参数用于向上个活动返回处理结果,一般只使用RESULT OK或RESULT_CANCELED这两个值,第二个参数则把带有数据的Intent传递回去。
现在当我们返回上一个活动时就会正常返回值了。