registerForActivityResult 用法详解及适配 Android 10、11

Android registerForActivityResults使用详解以及实现原理 /这个分发ActivityResult,主要通过key开判断的,如果处理了就返回true,否则交给父类处理。//需要传递Request用于解析Intent和解析上个Activity返回的结果。//其中mActivityResultRegistry是final变量。//将启动Activiity的key存储起来,用于后面结果回调使用。//以下方法的目的就是创建Intent并启动Activity。//传入启动的Activity信息,来启动Activity。//后面启动Activity调用的方法实现。 阅读详情

自源码已废弃了 startActivityForResult 之后,如果想要启动一个 Activity 并获取返回结果,推荐使用 registerForActivityResult ,方法定义如下:

public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
        @NonNull ActivityResultContract<I, O> contract,
        @NonNull ActivityResultCallback<O> callback) {
    
}

其中 I 即 Input 指代输入,O 即 Output 指代输出。
输入的是 约定协议,输出的是 返回结果。
官网文档:获取 activity 的结果

在实际开发过程中,我们只要指定我们需要的 输入 和 输出 类型,然后在 callback 处理返回值就可以了。

下面以 Android 常用的 选择图片,选择图片并剪裁,拍照,拍照并剪裁 作为例子来体验下 registerForActivityResult 的用法:

效果图:

一、选择图片并剪裁

1. 定义输入输出的协议 SelectPhotoContract 和 CropPhotoContract
/**
 * 选择照片的协定
 * Input type  : Unit? 不需要传值
 * Output type : Uri?  选择完成后的 image uri
 */
class SelectPhotoContract : ActivityResultContract<Unit?, Uri?>() {

    @CallSuper
    override fun createIntent(context: Context, input: Unit?): Intent {
        return Intent(Intent.ACTION_PICK).setType("image/*")
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        "pick photo result: ${intent?.data}".logD()
        return intent?.data
    }
}

/**
 * 剪裁照片的协定
 * Input type  : CropParams 剪裁照片的相关参数
 * Output type : Uri?       照片剪裁完成后的uri
 */
class CropPhotoContract : ActivityResultContract<CropParams, Uri?>() {

    private var outputUri: Uri? = null

    @CallSuper
    override fun createIntent(context: Context, input: CropParams): Intent {
        // 获取输入图片uri的媒体类型
        val mimeType = context.contentResolver.getType(input.uri)
        // 创建新的图片名称
        val imageName = "${System.currentTimeMillis()}.${
            MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType)
        }"
        outputUri = if (input.extraOutputUri.isNotEmpty()) {
            // 使用指定的uri地址
            input.extraOutputUri
        } else {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                // Android 10 及以上获取图片uri
                val values = contentValuesOf(
                    Pair(MediaStore.MediaColumns.DISPLAY_NAME, imageName),
                    Pair(MediaStore.MediaColumns.MIME_TYPE, mimeType),
                    Pair(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
                )
                context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
            } else {
                Uri.fromFile(File(context.externalCacheDir!!.absolutePath, imageName))
            }
        }

        return Intent("com.android.camera.action.CROP")
            .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            .setDataAndType(input.uri, mimeType)
            .putExtra("outputX", input.outputX)
            .putExtra("outputY", input.outputY)
            .putExtra("aspectX", input.aspectX)
            .putExtra("aspectY", input.aspectY)
            .putExtra("scale", input.scale)
            .putExtra("crop", input.crop)
            .putExtra("return-data", input.returnData)
            .putExtra("noFaceDetection", input.noFaceDetection)
            .putExtra(MediaStore.EXTRA_OUTPUT, outputUri)
            .putExtra("outputFormat", input.outputFormat)
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        "crop photo outputUri : $outputUri".logD()
        return outputUri
    }
}

/**
 * 剪裁照片的参数
 */
class CropParams(
    val uri: Uri,
    val aspectX: Int = 1,
    val aspectY: Int = 1,
    @androidx.annotation.IntRange(from = 0, to = 1080)
    val outputX: Int = 250,
    @androidx.annotation.IntRange(from = 0, to = 1080)
    val outputY: Int = 250,
    val scale: Boolean = true,
    val crop: Boolean = true,
    val noFaceDetection: Boolean = true,
    val returnData: Boolean = false,
    val outputFormat: String = Bitmap.CompressFormat.JPEG.toString(),
    val extraOutputUri: Uri? = null
)
2. 定义 ActivityResultLauncher
// 剪裁图片 
val cropPhoto = registerForActivityResult(CropPhotoContract()) { uri: Uri? ->
    if (uri != null) {
        ivImage.setImageURI(uri)
    }
}

// 选择图片        
val selectPhoto = registerForActivityResult(SelectPhotoContract()) { uri: Uri? ->
    if (uri != null) {
   		// 返回的选择的图片uri
        if (needCrop) {
        	// 需要剪裁图片,再调用剪裁图片的launch()方法
            cropPhoto.launch(CropParams(uri))
        } else {
        	// 如果不剪裁图片,则直接显示
            ivImage.setImageURI(uri)
        }
    } else {
        "您没有选择任何图片".toast()
    }
}
3. 点击时调用 ActivityResultLauncher 的 launch() 方法
// 从相册选择图片
btnSelectPhoto.setOnClickListener {
    // 定义的是Unit?,直接传 null
    needCrop = false
    selectPhoto.launch(null)
}

// 从相册选择图片并剪裁
btnSelectPhotoWithCrop.setOnClickListener {
    needCrop = true
    selectPhoto.launch(null)
}

二、拍照 并 剪裁

1. 定义输入输出的协议 TakePhotoContract
/**
 * 拍照协定
 * Input type  : Unit? 不需要传值
 * Output type : Uri?  拍照完成后的uri
 */
class TakePhotoContract : ActivityResultContract<Unit?, Uri?>() {

    private var uri: Uri? = null

    @CallSuper
    override fun createIntent(context: Context, input: Unit?): Intent {
        val mimeType = "image/jpeg"
        val fileName = "${System.currentTimeMillis()}.jpg"
        uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // Android 10 及以上获取图片uri
            val values = contentValuesOf(
                Pair(MediaStore.MediaColumns.DISPLAY_NAME, fileName),
                Pair(MediaStore.MediaColumns.MIME_TYPE, mimeType),
                Pair(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM)
            )
            context.contentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
        } else {
            // Android 9 及以下获取图片uri
            FileProvider.getUriForFile(
                context, "${context.packageName}.fileprovider",
                File(context.externalCacheDir!!.absolutePath, fileName)
            )
        }
        return Intent(MediaStore.ACTION_IMAGE_CAPTURE).putExtra(MediaStore.EXTRA_OUTPUT, uri)
    }

    override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
        "take photo uri : $uri".logD()
        return uri
    }
}
2. 定义 ActivityResultLauncher
val takePhoto = registerForActivityResult(TakePhotoContract()) { uri: Uri? ->
    if (uri != null) {
        if (needCrop) {
            cropPhoto.launch(CropParams(uri))
        } else {
            ivImage.setImageURI(uri)
        }
    }
}
3. 点击时调用 ActivityResultLauncher 的 launch() 方法
// 拍照并剪裁图片 
btnTakePhotoWithCrop.setOnClickListener {
    if (!BaseApp.instance.packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
        "设备未安装相机应用,无法拍照".toast()
        return@setOnClickListener
    }
    needCrop = true
    takePhoto.launch(null)
}

androidx 包中已经预定义了一些常用的 默认协定 ,可以参照其实现自定义协定。

查看完整示例代码:RegisterForResultActivity

registerForActivityResult方法介绍以及封装,解决点击事件中无法调用问题 在API 29 之前的版本中,跳转 Activity 获取返回结果使用的是startActivityForResult 方法,而 startActivityForResult 方法在API 29 中废弃,为过时方法,而谷歌推出 registerForActivityResult 方法来替代。这种方式需要重写 onActivityResult 方法,然后判断 requestCode 和 resultCode 的方式处理回调,流程麻烦了一点且不合时宜。 阅读详情

相关推荐

Android startActivityForResult 过时的替代方法。registerForActivityResult用法

由于startActivityForResult()方法不再推荐使用,谷歌工程师推荐使用registerForActivityResult方法。页面A向页面B跳转并传递数据,页面B处理完再跳转到页面A,同时把数据传递给页面A。

wangruil的博客 1596

安卓 onActivityResult 废弃,registerForActivityResult 使用详解

registerForActivityResult 是 Activtity 的一个方法,它可以生成一个对象,该对象的 launch 方法可以启动一次 Activtity 调用流程。该对象可以启动一个 Activtity 并与之绑定,这样,将这个启动的 Activtity 回传时,接收回传数据的代码就无需使用请求码了。可以向 launch 提供一个实参来表示本次 Activtity 调用流程的输入。这个输入可以是任意类型,也可以为 null。// 这里的 this 指向的是一个 Activity。

暗诺星刻的博客 1万+

Android 利用 registerForActivityResult() 实现高效图片选择与权限管理

本文详细介绍了Android开发中如何利用registerForActivityResult() API实现高效的图片选择和权限管理。通过对比传统startActivityForResult方法,阐述了新API在代码结构清晰度、生命周期安全性和契约式编程方面的优势,并提供了从系统相册选图、调用相机拍照到处理图片旋转及适配Android 14+权限模型的完整实战方案。

jupi8的博客 670

registerForActivityResult用法详解(Kotlin)

registerForActivityResult() 是startActivity() 的替换方法,它囊括了更多的功能回调,并且可以赋值给对象,通过 xxx.lunch() 方法重复使用。注意:多权限请求 返回的是map类型参数,所以需要获取map中所有的value来进行判断是否拿到所有权限。启动:在请求前需要先请求 Manifest.permission.READ_CONTACTS 权限。TakePicturePreview() 方法 是直接获取的相机预览界面,返回bitmap。跳转activity。

oxygen112的博客 1万+

Android开发中registerForActivityResult的实战应用指南

本文详细介绍了Android开发中registerForActivityResult的实战应用,包括其优势、Kotlin和Java实现方式、常见问题与最佳实践。作为startActivityForResult的现代替代方案,registerForActivityResult提供了更安全的生命周期管理和更清晰的代码结构,特别适合处理Activity间数据传递和权限请求等场景。

weixin_29280657的博客 222

Android:registerForActivityResult

中我们提到过Fragment中的onActivityResult已经废弃了,推荐使用registerForActivityResult去注册一个ActivityResultContract契约,从而启动一个forResult的Activity来达到目的,所以这里就看看这个流程是如何进行的。在MainActivity执行commitNow的时候,就会执行到Fragment的performAttach方法,这里改变了mState的值。对于接收返回的result,道理类似,大家可以根据断点堆栈了解一下。

bdmh的专栏 1442

Android registerForActivityResult 详解

当内置 Contract 无法满足需求时,可以通过继承实现自定义 Contract。方法调用时机作用launch()调用时根据输入 I 生成启动目标组件的 Intent目标组件关闭时将 resultCode 和 Intent 解析为输出 O。

2501_93275026的博客 430

registerForActivityResult:使用android中的自定义合同新注册活动结果

registerForActivityResult:使用android中的自定义合同新注册活动结果

startActivity和registerForActivityResult的用法

在 Android Kotlin 开发中,和是启动新 Activity 并处理返回结果的两种方式。

XHRK1的博客 1121

KiCad插件安装太慢?试试华秋版,再手把手教你装这5个实用插件

本文介绍了KiCad华秋发行版如何解决插件安装慢的问题,并详细推荐了5个实用插件及其安装方法。华秋版优化了国内用户的下载速度,预装了常用扩展包,包括BOM生成器、3D模型增强工具等,显著提升PCB设计效率。

weixin_29184075的博客 547

脱壳--02.exe

程序开始 使用OD打开程序 发现无法利用esp定律 程序直接运行 查找模块间调用 随便找到一个函数的调用 发现是FF15方式调用 所以是vs的程序 vs程序大致分成两种 vs20xx (特征函数:GetSystemTimeAsFileTime)和 vc++6.0(特征函数:GetVersion) 通过链接器版本 发现是vc6.0 直接在GetVersion上下断点 重新运行程序 断点断下 返回到调用处 vc6.0和易语言的第一个CALL都是GetVers...

weixin_45012273的博客 1112

Android registerForActivityResult详解

/ 自定义一个获取用户名的Contract@Override@Override= null) {// 使用= null) {textView.setText("欢迎:" + username);维度传统方式注册方式requestCode常量结果处理集中式onActivityResult分散式,各业务独立类型安全手动解析IntentContract定义输入输出类型生命周期感知需要手动处理自动管理代码组织职责分散发起和结果绑定学习曲线简单。

2401_83326930的博客 207

【FPGA XDMA AXI Bridge 模式】PCIe:BARs 和 AXI:BARs 含义解析

Xilinx的 DMA/Bridge Subsystem for PCI Express IP核中,支持普通的XDMA模式,但是这种模式只允许主机端发起PCIe 读写请求,FPGA内部无法主动发起读写请求,也即FPGA无法主动读写HOST的内存。而该IP核的另一种模式,AXI Bridge模式则支持HOST主动读写,以及FPGA主动读写。该模式下有个参数需要配置,分别是PCIe:BARs以及AXI:BARs。而上述的普通模式只有PCIe:BARs需要配置。下面详细说说这两个参数的含义。

weixin_45888152的博客 3730

registerForActivityResult常规用法

registerForActivityResult常规用法 使用registerForActivityResult方法来注册回调。 此方法简化数据回调的写法,并且提供了多种用途。 registerForActivityResult常规用法: //registerForActivityResult只能在onCreate中注册。onstart之后就不能注册了 val register = registerForActivityResult(ActivityResultContracts.StartActivit

雨季余静的博客 8889

Akamai移动端Sensor数据采集与BMP风控机制深度解析

本文深度解析了Akamai在移动端风控中的核心机制,重点阐述了Sensor数据如何通过采集陀螺仪、加速度计等硬件信息,结合设备指纹生成连续且符合物理规律的行为轨迹。详细剖析了数据从采集、加密校验到通过BMP风控三重验证(校验位、时间差、数据逻辑)的完整流程,并提供了从模拟优化到自建风控模型的实用应对思路。

quiet的专栏 284

3D Gaussian Splatting:用于实时的辐射场渲染

3D Gaussian Splatting:用于实时的辐射场渲染 3d gaussian splatting for real-time radiance field rendering

m0_51976564的博客 1万+

Android onActivityResult的替代方法—registerForActivityResult

一、前言 今天新建项目引入 implementation "androidx.fragment:fragment-ktx:1.3.0"包后,发现startActivityForResult()、onActivityResult()、requestPermissions()、onRequestPermissionsResult()方法被标记为过时,取而代之的是新方法registerForActivityResult() 二、基本用法 registerForActivityResult(Acti

weixin_42046829的博客 5824

使用下一代的嵌入式IDE-PlatformIO 教程

1.生成工程 1.1 打开STM32CubeMX: 选择你的MCU,这里我用的是STM32F103RC RCC中开启外部HSE时钟,外部时钟比HSI更稳定些 开启DEBUG 4线 打开串口1用于打印调试信息,波特率115200,校验位0,停止位1 打开串口2用于MODBUS协议,波特率9600,校验位0,停止位1 接入RT-thread:参考官方文档 基于 CubeMX 移植 RT-Thread Nano 根据官方文档,需要1.取消生成HardFault_Handler、PendSV_Handler、Sy

jiladahe1997的博客 3万+

Android registerForActivityResult

新的系统中 startActivityForResult 已经被标记为不推荐的方法,推荐的替代方案是使用 registerForActivityResult。

jjf19891208的专栏 2384

ZYNQ千兆网UDP通信实战:从Vivado配置到LWIP优化全流程(附避坑指南)

本文详细介绍了在ZYNQ平台上实现千兆以太网UDP通信的全流程,包括Vivado硬件配置、LWIP协议栈优化及实战代码示例。通过关键参数调整和性能优化,系统吞吐量可提升至850Mbps以上,适用于高速网络通信场景。

weixin_29161785的博客 230

关于keil编译报.sct (7): error: L6236E: No section matches selector - no section to be FIRST/LAST.处理方法

使用keilUvision5向下兼容,选择S3C2440主款芯片编译运行汇编语言。 出现了一个错误: . \objectslex3-2.sct (7): error: L6236E: No section matches selector - no section to be FIRST/LAST. 我在网上搜了很多,没有找到适合修正我这里的错误的。故咨询陈老师,终于将这个错误解决。 错误如下: 修改过程: 打开小仙女棒 将linker的Use Memory Layout fromTarget Dial

weixin_45865666的博客 9523

RegisterForActivityResult介绍

RegisterForActivityResult介绍1. 添加引用库2. 相关类和方法介绍2.1 ActivityResultContract2.2 ActivityResultCallback3. 示例4. 官方的封装4.1 实现startActivityForResult4.2 实现requestPermissions 首先介绍一下其作用: 它可以取代 startActivityForResult方法,获取另一个Activity的返回结果。 它可以取代 requestPermissions方法,用

chenrenxiang的专栏 9279

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

Android 带回调的启动Activity 推荐使用registerForActivityResult

今天无意间发现平常使用的startActivityForResult(intent,code)过时了,然后点进看: /** * {@inheritDoc} * * @deprecated use * {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)} * passing in a {@link StartActivityForRe...

Ikulm的博客 1万+

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

Android使用registerForActivityResult动态申请权限

前言 这几天在做一个小工具app,结果在fragment里面动态申请权限提示原有的申请方法已经弃用,还画了很明显的删除线。。。这叫一个强迫症的我怎么受得了。赶紧网上找资料也找不出什么结果,看了官方文档才发现了有registerForActivityResult这么一个神奇好用的函数,可以代替我们现有的startActivityForResult和权限申请函数。 那么下面就分两种情况来讲一下如何使用这个函数动态申请权限。 一、申请单个权限 这是函数的原型: @NonNull @Override

weixin_50285953的博客 6807

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

深入解析 registerForActivityResult

深入解析 registerForActivityResult 简介 registerForActivityResult方法是官方推出的用于在ComponetActivity和Fragment中替代startActivityForResult方法的新api 官方描述:https://developer.android.google.cn/training/basics/intents/result#kotlin 解析 话不多说,我们先上一段官方代码 val getContent = registerF

SquareSponge的博客 4697

Android新API之registerForActivityResult

startActivityForResult在api29中提示已过时,官方给出的替代方案是上面第二个红框的方法registerForActivityResult

weixin_38372716的博客 3880
上一篇: Android抓包获取网络接口数据,轻松集成AndroidToolkit
下一篇: Swift 基本数据类型
Lucky_William
博客等级 码龄11年 161粉丝 57原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值