registerForActivityResult使用
目录
针对 activity 结果注册回调
启动 activity 以获取其结果
在单独的类中接收 activity 结果
测试
创建自定义协定
registerForActivityResult()是startActivityForResult()的替代,简化了数据回调的写法
启动另一个 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 的逻辑仅基于用户输入内容或其他业务逻辑也是如此。
位于 ComponentActivity 或 Fragment 中时,Activity Result API 会提供 registerForActivityResult() API,用于注册结果回调。registerForActivityResult() 接受 ActivityResultContract 和 ActivityResultCallback 作为参数,并返回 ActivityResultLauncher,供您用来启动另一个 activity。
ActivityResultContract 定义生成结果所需的输入类型以及结果的输出类型。这些 API 可为拍照和请求权限等基本 intent 操作提供默认协定。您还可以创建自己的自定义协定。
ActivityResultCallback 是单一方法接口,带有 onActivityResult() 方法,可接受 ActivityResultContract 中定义的输出类型的对象:
val getContent = registerForActivityResult(GetContent()) { 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(),如以下示例所示:
val getContent = registerForActivityResult(GetContent()) { uri: Uri? -> // Handle the returned Uri } override fun onCreate(savedInstanceState: Bundle?) { // ... val selectButton = findViewById<Button>(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("image/*") } }
除了传递输入内容之外,launch() 的重载版本还允许您传递 ActivityOptionsCompat。
注意:由于在调用 launch() 与触发 onActivityResult() 回调的两个时间点之间,您的进程和 activity 可能会被销毁,因此,处理结果所需的任何其他状态都必须与这些 API 分开保存和恢复。
在单独的类中接收 activity 结果
虽然 ComponentActivity 和 Fragment 类通过实现 ActivityResultCaller 接口来允许您使用 registerForActivityResult() API,但您也可以直接使用 ActivityResultRegistry 在未实现 ActivityResultCaller 的单独类中接收结果。
例如,您可能需要实现一个 LifecycleObserver,用于处理协定的注册和启动器的启动:
class MyLifecycleObserver(private val registry : ActivityResultRegistry) : DefaultLifecycleObserver { lateinit var getContent : ActivityResultLauncher<String> override fun onCreate(owner: LifecycleOwner) { getContent = registry.register("key", owner, GetContent()) { uri -> // Handle the returned Uri } } fun selectImage() { getContent.launch("image/*") } } class MyFragment : Fragment() { lateinit var observer : MyLifecycleObserver override fun onCreate(savedInstanceState: Bundle?) { // ... observer = MyLifecycleObserver(requireActivity().activityResultRegistry) lifecycle.addObserver(observer) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { val selectButton = view.findViewById<Button>(R.id.select_button) selectButton.setOnClickListener { // Open the activity to select an image observer.selectImage() } } }
使用 ActivityResultRegistry API 时,强烈建议您使用可接受 LifecycleOwner 作为参数的 API,因为 LifecycleOwner 会在 Lifecycle 被销毁时自动移除已注册的启动器。不过,如果 LifecycleOwner 不存在,每个 ActivityResultLauncher 类都允许您手动调用 unregister() 作为替代。
测试
默认情况下,registerForActivityResult() 会自动使用 activity 提供的 ActivityResultRegistry。此外,它还提供了一个重载,让您可以传入自己的 ActivityResultRegistry 实例,该实例可用于测试您的 activity 结果调用,无需实际启动另一个 activity。
测试应用的 fragment 时,使用 FragmentFactory 将 ActivityResultRegistry 传入该 fragment 的构造函数即可提供测试 ActivityResultRegistry。
注意:任何允许您在测试中注入单独 ActivityResultRegistry 的机制都足以支持您测试 activity 结果调用。
例如,使用 TakePicturePreview 协定获取图片缩略图的 fragment 可能按类似如下所示的方式编写:
class MyFragment( private val registry: ActivityResultRegistry ) : Fragment() { val thumbnailLiveData = MutableLiveData<Bitmap?> val takePicture = registerForActivityResult(TakePicturePreview(), registry) { bitmap: Bitmap? -> thumbnailLiveData.setValue(bitmap) } // ... }
创建专用于测试的 ActivityResultRegistry 时,必须实现 onLaunch() 方法。您的测试实现可以直接调用 dispatchResult(),而不是调用 startActivityForResult(),从而提供要在测试中使用的确切结果:
val testRegistry = object : ActivityResultRegistry() {override fun <I, O> onLaunch(requestCode: Int,contract: ActivityResultContract<I, O>,input: I,options: ActivityOptionsCompat?) {dispatchResult(requestCode, expectedResult)}
}
完整的测试会产生预期的结果,构造一个测试 ActivityResultRegistry,将其传递给 fragment,直接触发启动器或通过 Espresso 等其他测试 API 触发启动器,然后验证结果:
@Test
fun activityResultTest {// Create an expected result Bitmapval expectedResult = Bitmap.createBitmap(1, 1, Bitmap.Config.RGBA_F16)// Create the test ActivityResultRegistryval testRegistry = object : ActivityResultRegistry() {override fun <I, O> onLaunch(requestCode: Int,contract: ActivityResultContract<I, O>,input: I,options: ActivityOptionsCompat?) {dispatchResult(requestCode, expectedResult)}}// Use the launchFragmentInContainer method that takes a// lambda to construct the Fragment with the testRegistrywith(launchFragmentInContainer { MyFragment(testRegistry) }) {onFragment { fragment ->// Trigger the ActivityResultLauncherfragment.takePicture()// Verify the result is setassertThat(fragment.thumbnailLiveData.value).isSameInstanceAs(expectedResult)}}
}
创建自定义协定
虽然 ActivityResultContracts 包含一些预先构建的可用 ActivityResultContract 类,但您可以使用自己的协定,提供您所需要的精确类型安全 API。
每个 ActivityResultContract 都需要定义输入和输出类,如果您不需要任何输入,可使用 Void(在 Kotlin 中,使用 Void? 或 Unit)作为输入类型。
每个协定都必须实现 createIntent() 方法,该方法接受 Context 和输入内容作为参数,并构造将与 startActivityForResult() 配合使用的 Intent。
每个协定还必须实现 parseResult(),这会根据指定的 resultCode(如 Activity.RESULT_OK 或 Activity.RESULT_CANCELED)和 Intent 生成输出内容。
如果无需调用 createIntent()、启动另一个 activity 并借助 parseResult() 来构建结果即可确定指定输入内容的结果,协定可以选择性地实现 getSynchronousResult()。
class PickRingtone : ActivityResultContract<Int, Uri?>() { override fun createIntent(context: Context, ringtoneType: Int) = Intent(RingtoneManager.ACTION_RINGTONE_PICKER).apply { putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, ringtoneType) } override fun parseResult(resultCode: Int, result: Intent?) : Uri? { if (resultCode != Activity.RESULT_OK) { return null } return result?.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI) } }
如果您不需要自定义协定,则可以使用 StartActivityForResult 协定。这是一个通用协定,它可接受任何 Intent 作为输入内容并返回 ActivityResult,让您能够在回调中提取 resultCode 和 Intent,如以下示例所示:
val startForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult -> if (result.resultCode == Activity.RESULT_OK) { val intent = result.data // Handle the Intent } } override fun onCreate(savedInstanceState: Bundle) { // ... val startButton = findViewById(R.id.start_button) startButton.setOnClickListener { // Use the Kotlin extension in activity-ktx // passing it the Intent you want to start startForResult.launch(Intent(this, ResultProducingActivity::class.java)) } }
相关文章:
registerForActivityResult使用
目录 针对 activity 结果注册回调 启动 activity 以获取其结果 在单独的类中接收 activity 结果 测试 创建自定义协定 registerForActivityResult()是startActivityForResult()的替代,简化了数据回调的写法 启动另一个 activity&#x…...
工作中,python真的有用吗?
普通上班族学Python有用吗? 那么,我也在这里提出一个问题:Python究竟适不适合办公人士来学习,以及学了之后究竟能不能给我的工作来带质一般的飞跃? 以我的亲身经历为例,我可以很负责的告诉大家,…...
固态继电器控制电路
固态继电器控制电路 固态继电器(SSR)的种类和型号很多,因此其输入控制方法和控制电路也相应众多。固态继电器(SSR)的共同特点在于驱动电流或驱动电压小,即只需输入一个小信号即可控制SSR的开关。 如果需要…...
数仓、数据湖、湖仓一体、数据网格的探索与研究
第一代:数据仓库 定义 为解决数据库面对数据分析的不足,孕育出新一类产品数据仓库。数据仓库(Data Warehouse)是一个面向主题的、集成的、相对稳定的、反映历史变化的数据集合,用于支持管理决策和信息的全局共享。 数…...
设计模式系列 - 备忘录模式
介绍&定义 备忘录模式,也叫快照(Snapshot)模式,英文翻译是 Memento Design Pattern。在 GoF 的《设计模式》一书中,备忘录模式是这么定义的: Captures and externalizes an object’s internal state…...
详细介绍React生命周期和diffing算法
事件处理 1.通过onXxx属性指定事件处理函数(注意大小写) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件 —— 为了更好的兼容性;React中的事件是通过事件委托方式处理的(委托给组件最外层的元素) ——为了的高效。 2.通过event.target得到发生事件的DOM…...
面向对象的特点
1、什么是对象对象的含义是指具体的某一个事物,即在现实生活中能够看得见摸得着的事物。在面向对象程序设计中,对象所指的是计算机系统中的某一个成分。在面向对象程序设计中,对象包含两个含义,其中一个是数据,另外一个…...
智慧校园平台源码 智慧教务 智慧电子班牌系统
系统介绍 智慧校园系统是通过信息化手段,实现对校园内各类资源的有效集成 整合和优化,实现资源的有效配置和充分利用,将校务管理过程的优化协调。为校园提供数字化教学、数字化学习、数字化科研和数字化管理。 致力于为家长和教师提供一个全方位、多层…...
Vue篇.03-组合式API [setup()]
单文件组件(1)<script setup><script setup> 是在单文件组件 (SFC) 中使用组合式 API 的编译时语法糖。当同时使用 SFC 与组合式 API 时该语法是默认推荐启用该语法,需要在 <script> 代码块上添加 setup attribute, 里面的代码会被编译成组件 s…...
QHashIterator-官翻
QHashIterator Class template <typename Key, typename T> class QHashIterator QHashIterator 类为 QHash 和 QMultiHash 提供 Java 风格的常量迭代器。更多内容… 头文件:#include qmake:QT core 所有成员列表,包括继承的成员废弃的成员 公共成员函数…...
[qiankun]-部署后线上问题
[qiankun]-部署后线上问题微服务加载问题-现象1现象描述问题分析解决方案微服务加载问题-现象2现象描述问题分析微服务加载问题-现象3现象描述分析解决方案属于项目打包后,部署到服务器上,所遇到的部分问题 微服务加载问题-现象1 现象描述 项目部署实…...
位图数组 布隆过滤器
文章目录位图数组获取索引获取索引状态设置索引状态布隆过滤器特点大致原理位图数组 一个int类型的整数用4字节,也就是32个bit位来表示,将整数类型的数组转换成位图数组,那么存储长度将变为原来的32倍 arr[0] 表示0-31 arr[1] 表示32-63 //...获取索引…...
多线程Thread常用方法和状态
Thread类 及常见方法 1、常见构造方法 方法说明Thread()创建线程对象Thread(Runnable target)使用 Runnable 对象创建线程对象Thread(String name)创建线程对象,并命名Thread(Runnable target, String name)使用 Runnable 对象创建线程对象,并命名Thre…...
Codeforces Round #836 (Div. 2)
A SSeeeeiinngg DDoouubbllee 题意:告诉你一个字符串。若该串上每一位上的字母都可以出现两次,求回文串 思路:正向再反向输出s即可 #include <bits/stdc.h> #define lowbit(x) x&(-x) #define ios cin.sync_with_stdio(false)…...
Python学习之项目实践: 写一个MP3播放器
下面呢,是一个 Python MP3 播放器,它使用 pygame 模块来实现音乐播放功能: import pygame class MP3Player: """ MP3 播放器类 """ def __init__(self): pygame.mixer.init() def play(self, file_path): &quo…...
RocketMQTemplate 实现消息发送
代码托管于gitee:easy-rocketmq 文章目录一、前置工作二、消费者三、生产者1. 普通消息2. 过滤消息3. 同步消息4. 延时消息5. 批量消息6. 异步消息7. 单向消息8. 顺序消息9. 事务消息概要Demo源码解读一、前置工作 1、导入依赖 <dependency><groupId>…...
教师干货丨这5款微课必备提效神器,我要告诉全世界!
微课是一种短小精悍的视频教学形式,其设计和演示因特别简洁明了而被定义为“小而美”。由于只在几分钟时间内向学生传授所需知识,微课为学习者提供更多的选择机会和时间节约的便利,而这种趋势已经逐渐在新的社交媒体环境中显现出来。在制作微…...
timm使用swin-transformer
1.安装 pip install timm2.timm中有多少个预训练模型 #timm中有多少个预训练模型 model_pretrain_list timm.list_models(pretrainedTrue) print(len(model_pretrain_list), model_pretrain_list[:3])3加载swin模型一般准会出错 model_ft timm.create_model(swin_base_pat…...
【java基础】java八大基本数据类型和运算符
文章目录说明八大基本数据类型整型浮点型字符型布尔类型类型转换java运算符基础运算符二元运算符自增自减运算符关系和boolean运算符三元运算符位运算符运算符优先级说明 这里介绍java的八大基本数据类型和运算符 八大基本数据类型 java中有八大数据类型,4个整型…...
Mybatis源码学习笔记(四)之Mybatis执行增删改查方法的流程解析
1 Mybatis流程解析概述 Mybatis框架在执行增伤改的流程基本相同, 很简单,这个大家只要自己写个测试demo跟一下源码,基本就能明白是怎么回事,查询操作略有不同, 这里主要通过查询操作来解析一下整个框架的流程设计实现。 2 Mybat…...
React 第五十五节 Router 中 useAsyncError的使用详解
前言 useAsyncError 是 React Router v6.4 引入的一个钩子,用于处理异步操作(如数据加载)中的错误。下面我将详细解释其用途并提供代码示例。 一、useAsyncError 用途 处理异步错误:捕获在 loader 或 action 中发生的异步错误替…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
Web后端基础(基础知识)
BS架构:Browser/Server,浏览器/服务器架构模式。客户端只需要浏览器,应用程序的逻辑和数据都存储在服务端。 优点:维护方便缺点:体验一般 CS架构:Client/Server,客户端/服务器架构模式。需要单独…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
