启动另一个 activity(无论是您应用中的 activity 还是其他应用中的 activity)不一定是单向操作。您也可以启动另一个 activity 并接收返回的结果。例如,您的应用可启动相机应用并接收拍摄的照片作为结果。或者,您可以启动“通讯录”应用以便用户选择联系人,并且您将接收联系人详细信息作为结果。
虽然所有 API 级别的 Activity 类均提供底层 startActivityForResult() 和 onActivityResult() API,但我们强烈建议您使用 AndroidX Activity 和 Fragment 中引入的 Activity Result API。
Activity Result API 提供了用于注册结果、启动结果以及在系统分派结果后对其进行处理的组件。
针对 activity 结果注册回调
在启动 activity 以获取结果时,可能会出现您的进程和 activity 因内存不足而被销毁的情况;如果是使用相机等内存密集型操作,几乎可以确定会出现这种情况。
因此,Activity Result API 会将结果回调从您之前启动另一个 activity 的代码位置分离开来。由于在重新创建进程和 activity 时需要使用结果回调,因此每次创建 activity 时都必须无条件注册回调,即使启动另一个 activity 的逻辑仅基于用户输入内容或其他业务逻辑也是如此。
ActivityResultContract 定义生成结果所需的输入类型以及结果的输出类型。这些 API 可为拍照和请求权限等基本 intent 操作提供默认协定。您还可以创建自己的自定义协定。
ActivityResultCallback 是单一方法接口,带有 onActivityResult() 方法,可接受 ActivityResultContract 中定义的输出类型的对象:
Kotlin
val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->
// Handle the returned Uri
}Java
// GetContent creates an ActivityResultLauncher to allow you to pass
// in the mime type you'd like to allow the user to select
ActivityResultLauncher mGetContent = registerForActivityResult(new GetContent(),
new ActivityResultCallback() {
@Override
public void onActivityResult(Uri uri) {
// Handle the returned Uri
}
});
如果您有多个使用不同协定或需要单独回调的 activity 结果调用,则可以多次调用 registerForActivityResult(),以注册多个 ActivityResultLauncher 实例。每次创建 fragment 或 activity 时,都必须按照相同的顺序调用 registerForActivityResult(),才能确保将生成的结果传递给正确的回调。
在 fragment 或 activity 创建完毕之前可安全地调用 registerForActivityResult(),因此,在为返回的 ActivityResultLauncher 实例声明成员变量时可以直接使用它。
注意:虽然在 fragment 或 activity 创建完毕之前可安全地调用 registerForActivityResult(),但在 fragment 或 activity 的 Lifecycle 变为 CREATED 状态之前,您无法启动 ActivityResultLauncher。
启动 activity 以获取其结果
虽然 registerForActivityResult() 会注册您的回调,但它不会启动另一个 activity 并发出结果请求。这些操作由返回的 ActivityResultLauncher 实例负责。
如果存在输入内容,启动器会接受与 ActivityResultContract 的类型匹配的输入内容。调用 launch() 会启动生成结果的过程。当用户完成后续 activity 并返回时,系统将执行 ActivityResultCallback 中的 onActivityResult(),如以下示例所示:
Kotlin
val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->
// Handle the returned Uri
}
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val selectButton = findViewById(R.id.select_button)
selectButton.setOnClickListener {
// Pass in the mime type you'd like to allow the user to select
// as the input
getContent.launch("