背景
针对Activity传递数据,常见方式是:
步骤1:通过Intent存储携带数据; 步骤2:使用startActivityForResult()启动Activity; 步骤3:通过onActivityResult()接收返回结果。
问题
onActivityResult()回调里存在大量的业务回调嵌套,耦合严重。
解决方案
Google官方推荐:「Activity Results API」。
❝注:Google在androidx.activity和fragment的alpha02版本中,已经废弃了startActivityForResult()、onActivityResult()。
❞
简介
Google官方推荐的用于Activity、Fragment获取返回结果的方式。(用于替代onActivityResult())
优点
使用方便 降低了业务之间的耦合 减少了样板代码(如定义大量requestCode常量用于区分业务)
使用介绍
Activity Results API 中有两个核心使用组件:
ActivityResultContract ActivityResultLauncher
ActivityResultContract
是一个抽象类,需要继承来创建自己的协议,定义了如何传递数据和如何处理返回的数据。Google预置了大量常用的Contract供开发者直接使用,具体如下:
// 最常用、最通用
StartActivityForResult()
// 不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定。
// 权限相关
RequestPermission()
// 用于请求单个权限
RequestMultiplePermissions()
// 用于请求一组权限
// 多媒体相关
TakePicturePreview()
// 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片
TakePicture()
// 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功。
TakeVideo()
// 调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图。
// 文档相关
CreateDocument()
// 提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri。
OpenMultipleDocuments()
// 提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式。
OpenDocumentTree()
// 提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。
当然,也可以自定义ActivityResultContract,具体定义步骤如下:
// 步骤1:新建一个Contract类,继承自ActivityResultContract<I,O>
// 参数说明:
// I:输入的类型
// O:输出的类型
class MyActivityResultContract: ActivityResultContract<String,String>(){
// 步骤2:实现createIntent()
// 输入类型I作为createIntent的参数
override fun createIntent(context: Context, input: String?): Intent {
return Intent(context,SecondActivity::class.java).apply {
putExtra("test",input)
}
}
// 步骤3:实现parseResult()
// 输出类型O作为parseResult方法的返回值
override fun parseResult(resultCode: Int, intent: Intent?): String? {
val data = intent?.getStringExtra("result")
return if (resultCode == Activity.RESULT_OK && data != null) data
else null
}
}
在上述例子:
输入输出类型都是String; 在createIntent()通过Intent携带了参数为test的数据; 在parseResult()通过Intent获得了返回的数据result。
ActivityResultLauncher
启动器,通过调用ActivityResultLauncher.launch()来启动页面跳转(作用相当于原来的startActivity())。
使用步骤
步骤1:注册协议Contract(可采用系统内置的 or 开发者自定义) 步骤2:创建启动器ActivityResultLauncher & 设置回调 步骤3:打开新Acitivity时传递数据 步骤4:关闭新Activity时回传数据
使用示例
此处展示的是:
从Activity1打开Activity2时传递数据:carsonho_request 从Activity2关闭回到Activity1时回传数据:carsonho_response
具体使用代码
// 步骤1:注册协议Contract
// 可采用系统内置的 or 开发者自定义
// 此处采用系统内置的StartActivityForResult()展示
// 步骤2:创建启动器ActivityResultLauncher & 设置回调
private val myActivityLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ activityResult ->
if(activityResult.resultCode == Activity.RESULT_OK){
// 收到回调数据result:carsonho_response
val result = activityResult.data?.getStringExtra("result")
}
}
// 步骤3:从Activity1打开Activity2时传递数据,即从Activity1打开Activity2时
button.setOnClickListener {
val intent = Intent(this,SecondActivity::class.java).apply {
putExtra("test","carsonho_request")
}
myActivityLauncher.launch(intent)
}
// 步骤4:打开新Activity时接收数据,即打开Activity2时
val test = intent.getStringExtra("test")
// 步骤5:关闭新Activity时回传数据,即从Activity2关闭回到Activity1时
button.setOnClickListener {
val intent = Intent().apply {
putExtra("result","carsonho_response")
}
setResult(Activity.RESULT_OK,intent)
finish()
}
「Carson每天带你学习一个Android知识点」,长按扫描关注公众号。同时,期待您精彩文章的投稿:真诚邀请您来分享
最后福利:学习资料赠送
福利:由本人亲自撰写 & 整理的「Android学习方法资料」 数量:10名 参与方式:「点击文章右下角”在看“ -> 回复截图到公众号 即可,我将从中随机抽取」 点击“在看”就能升职 & 加薪水哦!