还在用startActivityForResult处理数据传递?试试ActivityResultContract吧

简介: 还在用startActivityForResult处理数据传递?试试ActivityResultContract吧

ActivityResultContract是什么


很简单的一句话,ActivityResultContract是用来在大部分场景中对startActivityForResultonActivityResult进行替代的官方api

ActivityResultContract提供了一种类型安全的获取返回值的方式,比如拍照的api会返回泛型指定的bitmap。这避免了我们手动处理onActivityResult回调导致的各种问题。

当然了我认为ActivityResultContract最好的地方就是省心,尤其对于系统预置的集中ActivityResultContract,只需要两步模板代码即可实现功能。


自定义一个ActivityResultContract


要实现自定义行为需要先自定义一个ActivityResultContract类,定义如下:

  1. 集成ActivityResultContract类

ActivityResultContract类中有两个泛型,第一个泛型是I,第二个泛型是O,I表示输入也就是我们启动activity需要putExtra的内容,O表述输入即onActivityResult返回的数据

ActivityResultContract有两个方法

  • createIntent表示创建启动activityIntent,其中方法的第二个参数可用于传给待启动activity的参数
  • parseResult表示对返回数据的解析,方法的返回值就是registerForActivityResult中回调的数据
class CustomResultContracts : ActivityResultContract<Int, String>() {
    override fun createIntent(context: Context, input: Int?): Intent {
        return Intent(context, DestinishActivity::class.java).putExtra("input",input)
    }
    override fun parseResult(resultCode: Int, intent: Intent?): String {
        return intent?.getStringExtra("data") ?: "未返回数据"
    }
}
复制代码
  1. 注册监听
private val customContract = registerForActivityResult(CustomResultContracts()){
        getData(14).content="自定义Contracts返回数据:$it"
        getData(14).notifyDataSetChange()
    }
复制代码
  1. 启动activity
customContract.launch(1)
复制代码


官方提供的预置ActivityResultContract


StartActivityForResult启动activity返回结果

本例调用方法后会启动一个activity,新的activity点击返回数据将数据返回到列表中展示

  1. 代码

注册代码

//注册结果监听
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            if (it.resultCode == 3) {
                showResult(it.data?.getStringExtra("data"))
            }
        }
复制代码

启动代码

//启动activity,参数传intent
startForResult.launch(Intent(this@MainActivity, DestinishActivity::class.java))
复制代码
  1. 效果

image.png


TakePicturePreview跳转拍照页面

跳转到拍照页面,会返回一个Bitmap,拍摄的图片不会被持久化到磁盘中

  1. 代码
registerForActivityResult(ActivityResultContracts.TakePicturePreview()) {
            getData(1).let {
                it.notifyDataSetChange()
            }
        }
复制代码

模拟器录制不变,暂无效果图


TakePicture拍摄预览图片

TakePicture方法会跳转到系统相机拍摄一张照片,返回boolean值,图片会被存储到我们指定的目录中

  1. 代码
private val takePreviewPic = registerForActivityResult(ActivityResultContracts.TakePicture()) {
        logEE("搞预览图片成功")
    }
复制代码


CaptureVideo拍摄视频

拍摄代码,需要说明的是拍摄视频完成后会需要等待较长时间,等待手机处理完视频的存储

private val captureVideo = registerForActivityResult(ActivityResultContracts.CaptureVideo()) {
        logEE("拍摄视频成功:$it")
    }
复制代码

模拟器录制不变,暂无效果图


RequestPermission请求权限

非常简洁的方式实现权限申请

  1. 申请权限代码
cameraPermission.launch(Manifest.permission.CAMERA)
复制代码
  1. 注册申请权限监听
private val cameraPermission =
        registerForActivityResult(ActivityResultContracts.RequestPermission()) {
            getData(3).apply {
                content = "请求相机权限结果$it"
                notifyDataSetChange()
            }
        }
复制代码
  1. 效果

image.png


RequestMultiplePermissions请求多个权限

  1. 调用申请多个权限代码
mutlePermission.launch(
                    arrayOf(
                        Manifest.permission.CAMERA,
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE
                    )
                )
复制代码
  1. 注册申请多个权限的代码
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) {
            var result = ""
            it.forEach { gaint ->
                result += "获取${gaint.key} 权限 ${if (gaint.value) "成功" else "失败"}"
            }
            getData(4).content = result
            getData(4).notifyDataSetChange()
        }
复制代码
  1. 效果

image.png


PickContact获取联系人

  1. 请求打开联系人选择页面
pickContact.launch(null)//参数传空
复制代码
  1. 监听获取联系人结果
private val pickContact = registerForActivityResult(ActivityResultContracts.PickContact()) {
        logEE(it.toString())
        getData(8).apply {
            content = it.toString()
            notifyDataSetChange()
        }
    }
复制代码
  1. 实现效果

image.png


GetContent打开文件浏览器

实现使用文件浏览器选择图片功能

  1. 打开文件浏览器
getContent.launch("image/*")
复制代码
  1. 处理返回结果
private val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) {
        logEE(it.toString())
    }
复制代码
  1. 实现效果

因为模拟器没有图片可选,所以没有内容展示

image.png

2021/08/06 更新新内容如下


Fragment中使用ActivityForResultContract


Fragment中的使用和activity中是一样的,直接放参考代码吧

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        view.findViewById<Button>(R.id.btn).setOnClickListener {
            request.launch(Intent(activity, DestinishActivity::class.java))//启动新activity
        }
    }
    /**
     * 注册结果监听
     */
    val request = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        logEE(it.data?.getStringExtra("data")!!)
    }
复制代码

最终效果和activity是一致的


两个Activity中不同Fragment如何通信


2021/12/11 更新新内容如下需要引入如下库

implementation 'androidx.fragment:fragment-ktx:1.3.0'
复制代码

我们建立如下图中的四个类

image.png

Comm1Activity中展示ActivityCommFragment1,Comm2Activity中展示ActivityCommFragment2

我们要做这样一个事情,在ActivityCommFragment1中打开 Comm2Activity并且把数据传到ActivityCommFragment2中,同时在ActivityCommFragment2中返回数据在 ActivityCommFragment1中收到返回的数据。

代码如下:

  1. 在ActivityCommFragment1中编写接收返回数据代码
private val launcher:ActivityResultLauncher<Intent> = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->
    if (result.resultCode == Activity.RESULT_OK){
        binding.tvSend.text = result.data?.getIntExtra("nums",-1).toString()
    }
}
复制代码
  1. ActivityCommFragment1中启动Comm2Activity
launcher.launch(Intent(requireContext(),Comm2Activity::class.java))
复制代码
  1. 在ActivityCommFragment2中返回数据的方法
binding.btnReturndata.setOnClickListener {
    requireActivity().setResult(Activity.RESULT_OK,Intent().apply {
        putExtra("nums",123)
    })
    requireActivity().finish()
}
复制代码

image.png



相关文章
|
Android开发
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
【Android App】蓝牙的设备配对、音频传输、点对点通信的讲解及实战(附源码和演示 超详细)
2944 1
|
Java
Call to ‘super()‘ must be first statement in constructor body
文章解释了在Java中子类构造函数中调用父类构造函数时,必须首先调用`super()`,且不能有返回值。
194 0
Call to ‘super()‘ must be first statement in constructor body
|
编解码 测试技术 Android开发
Android经典实战之用 CameraX 库实现高质量的照片和视频拍摄功能
本文详细介绍了如何利用CameraX库实现高质量的照片及视频拍摄功能,包括添加依赖、初始化、权限请求、配置预览与捕获等关键步骤。此外,还特别针对不同分辨率和帧率的视频拍摄提供了性能优化策略,确保应用既高效又稳定。
1456 1
Android经典实战之用 CameraX 库实现高质量的照片和视频拍摄功能
|
Android开发
Android中使用startActivityForResult启动活动
Android中使用startActivityForResult启动活动
|
Ubuntu Linux Shell
10-23|如何查看linux当前时间
10-23|如何查看linux当前时间
|
存储 安全 Java
Android DataStore:安全存储和轻松管理数据
Android DataStore:安全存储和轻松管理数据
|
NoSQL 关系型数据库 MySQL
关于项目中 Repository 层的思考
关于项目中 Repository 层的思考
202 0
|
前端开发 Shell PHP
Python(二十七)python raise语法!
Python可以使用raise手动抛出异常。 看到菜鸟教程里边对 raise 的这个定义的时候,我有点迷茫,我在极力的去避免异常出现,我为什么还要手动抛出异常呢? 1:raise 语句的基本语法格式: raise [exceptionName [(reason)]] 2:基本使用方法 (1):直接一个raise抛出异常 python 复制代码 try: i = 1 while(i < 10): raise print(i) i += 1 except: print('raise 手动抛出异常') 输出: bas
322 1
|
机器学习/深度学习 算法 安全
密码学系列之三:DES、AES、IDEA —— 一文搞懂分组密码
密码学系列之三:DES、AES、IDEA —— 一文搞懂分组密码
2811 0
|
Shell 开发工具 git
使用openwrt搭建编译环境,编译一个demo
使用openwrt搭建编译环境,编译一个demo
637 1