被动学习的Activity Result API
为何被动
原因其实挺无语的,在敲阳光沙滩app的时候,用到了获取相册图片,然后进行裁切,最后得到结果并设置到背景里。然后就发现了 ???startActivityForResult()为什么弃用了 然后新建了个项目又试了试
???这个没问题啊 然后找了找问题,最终发现
噢,原来是对应的jar包不一样 -。-
一看Lib库,擦,这是什么时候添加的(ˉ▽ˉ;)... 好吧,既然startActivityForResult()弃用了,那就看一眼推荐的用法
然后去文档里找一找
什么是Activity Result API
谷歌文档 文档地址1 Activity Result API:ComponentActivity 现在提供了一个 ActivityResultRegistry,让您无需替换 Activity 或 Fragment 中的方法,即可处理 startActivityForResult()+onActivityResult() 以及 requestPermissions()+onRequestPermissionsResult() 流程,通过 ActivityResultContract 提高了类型安全性,并提供了用于测试这些流程的钩子。请参阅更新后的获取 Activity 的结果一文。 文档地址2 虽然所有 API 级别的 Activity 类均提供底层 startActivityForResult() 和 onActivityResult() API,但我们强烈建议您使用 AndroidX Activity 和 Fragment 中引入的 Activity Result API。 Activity Result API 提供了用于注册结果、启动结果以及在系统分派结果后对其进行处理的组件。 位于 ComponentActivity 或 Fragment 中时,Activity Result API 会提供 registerForActivityResult() API,用于注册结果回调。registerForActivityResult() 接受 ActivityResultContract 和 ActivityResultCallback 作为参数,并返回 ActivityResultLauncher,供您用来启动另一个 activity。
好吗,看了下文档,发现这个Activity Results API 中两个重要的组件: 1. ==ActivityResultContract==:协议,是一个抽象类,它定义了如何传递数据和如何处理返回的数据,你需要继承它来创建自己的协议。 每个 ActivityResultContract 都需要定义输入和输出类,如果您不需要任何输入,可使用 Void(在 Kotlin 中,使用 Void? 或 Unit)作为输入类型。 2. ==ActivityResultLauncher==:启动器,调用ActivityResultLauncher的launch方法来启动页面跳转,作用相当于原来的startActivity()
好的,既然了解了一点基础,那就上手试一试
上手尝试
- 添加依赖 根据文档里的提示添加依赖
implementation 'androidx.activity:activity:1.2.0-beta01'
implementation 'androidx.fragment:fragment:1.3.0-beta01'
- 定义协议 新建一个Contract类,继承自ActivityResultContract<I,O>,其中,I是输入的类型,O是输出的类型。需要实现2个方法,createIntent和parseResult,输入类型I作为createIntent的参数,输出类型O作为parseResult方法的返回值,我用的输入输出类型都是String
class MyActivityResultContract : ActivityResultContract<String, String>() {
override fun createIntent(context: Context, input: String?): Intent {
return Intent(context, SecondActivity::class.java).apply {
putExtra("name", input)
}
}
override fun parseResult(resultCode: Int, intent: Intent?): String? {
val data = intent?.getStringExtra("result")
return if (resultCode == Activity.RESULT_OK && data != null) data
else null
}
}
- 注册协议 注册协议,使用registerForActivityResult方法,该方法由ComponentActivity或者Fragment提供,接受2个参数,第一个参数就是我们定义的Contract协议,第二个参数是一个回调ActivityResultCallback
,其中O就是前面Contract的输出类型
private val myActivityLauncher =
registerForActivityResult(MyActivityResultContract()) { result ->
textView1.text = "回传数据:$result"
}
- 调用启动器的launch方法开启界面跳转 启动界面
selectButton.setOnClickListener {
myActivityLauncher.launch("Hello,阳光沙滩")
}
接收界面
val name = intent.getStringExtra("name")
textView2.text = "接收到的数据为:$name"
button2.setOnClickListener {
val intent = Intent().apply {
putExtra("result", "Hello,阳光沙滩,我是回传的数据!")
}
setResult(Activity.RESULT_OK, intent)
finish()
}
- 结果展示
Activity Results API 预定义的 Contract
都定义在类ActivityResultContracts中,有以下这些Contract: ==StartActivityForResult==: 通用的Contract,不做任何转换,Intent作为输入,ActivityResult作为输出,这也是最常用的一个协定。 ==RequestMultiplePermissions==: 用于请求一组权限 ==RequestPermission==: 用于请求单个权限 ==TakePicturePreview==: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值为Bitmap图片 ==TakePicture==: 调用MediaStore.ACTION_IMAGE_CAPTURE拍照,并将图片保存到给定的Uri地址,返回true表示保存成功。 ==TakeVideo==: 调用MediaStore.ACTION_VIDEO_CAPTURE 拍摄视频,保存到给定的Uri地址,返回一张缩略图。 ==PickContact==: 从通讯录APP获取联系人 ==GetContent==: 提示用选择一条内容,返回一个通过ContentResolver#openInputStream(Uri)访问原生数据的Uri地址(content://形式) 。 默认情况下,它增加了Intent#CATEGORY_OPENABLE, 返回可以表示流的内容。 ==CreateDocument==: 提示用户选择一个文档,返回一个(file:/http:/content:)开头的Uri。 ==OpenMultipleDocuments==: 提示用户选择文档(可以选择多个),分别返回它们的Uri,以List的形式。 ==OpenDocumentTree==: 提示用户选择一个目录,并返回用户选择的作为一个Uri返回,应用程序可以完全管理返回目录中的文档。 上面这些预定义的Contract中,除了StartActivityForResult和RequestMultiplePermissions之外,基本都是处理的与其他APP交互,返回数据的场景,比如,拍照,选择图片,选择联系人,打开文档等等。使用最多的就是StartActivityForResult和RequestMultiplePermissions了。
总结
就这样意外的学习了一下Activity Results API ,虽然只是学习一些基础内容,但是收获还是不错的。文档中还有一些内容等着我去学习,这边分享的内容就这么多啦,希望看到的小伙伴有所收获。