1. 老的实现方式

日常开发中,实现页面传值,通常通过startActivityForResult和onActivityResult配合,通过判断requestCode处理不同的业务场景:

startActivityForResult(intent, requestCode)
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {super.onActivityResult(requestCode, resultCode, data)if(resultCode == Activity.RESULT_OK && requestCode == 100) {// 处理页面返回的参数}
}

2. 新Activity Result API

private val startForResult =registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->if (result.resultCode == Activity.RESULT_OK) {//页面返回值val data = result.data}}
// 打开页面
startForResult.launch(Intent(this, ActivityB::class.java))

上面的实现是不是简单明了,直接注册回调实现业务逻辑,有多个传值的业务就定义多个回调协定(ActivityResultContract),可以很好的单独处理,不用在onActivityResult里面通过requestCode判断,非常方便的实现业务解耦。

3.如何使用

3.1 添加依赖,Activity Result API是在Androidx Activity和Fragment中引入的

最新版本

    implementation "androidx.activity:activity-ktx:1.2.2"implementation "androidx.fragment:fragment-ktx:1.3.2"

3.2 注册协定,获取ActivityResultLauncher

private val selectData =registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->if (result.resultCode == Activity.RESULT_OK) {val data = result.data}}

3.3 构造Intent传递参数,启动页面

 btnA.setOnClickListener {val intent = Intent(this, ActivityB::class.java)selectData.launch(intent)}

启动一个activity需要一个laucher,这个laucher由registerForActivityResult返回,这个方法需要两个参数,一个参数为一个抽象类——ActivityResultContract<I, O>的实现,另一个参数是一个函数式接口的实现(用一个lambda表达式来代替)。

public abstract class ActivityResultContract<I, O> {/** Create an intent that can be used for {@link Activity#startActivityForResult} */public abstract @NonNull Intent createIntent(@NonNull Context context,@SuppressLint("UnknownNullness") I input);/** Convert result obtained from {@link Activity#onActivityResult} to O */@SuppressLint("UnknownNullness")public abstract O parseResult(int resultCode, @Nullable Intent intent);

第一个方法是配置结合input配置intent, 第二个方法是从intent取出数据返回。

第二个参数是对从intent取出的数据的处理。

因此:官方为我们提供了很多便捷的实现好的第一个参数

4. 已有的协定

预定义的Contract大伙都看出来,新的Activity Results API使用起来好像有点麻烦,每次都得定义Contract。Google肯定考虑到了这个问题的,于是,Google 预定义了很多Contract,把你们能想到的使用场景基本上都想到了,它们都定义在类ActivityResultContracts中,有以下这些Contract:StartActivityForResult()
RequestMultiplePermissions()
RequestPermission()
TakePicturePreview()
TakePicture()
TakeVideo()
PickContact()
CreateDocument()
OpenDocumentTree()
OpenMultipleDocuments()
OpenDocument()
GetMultipleContents()
GetContent()下面分别介绍一下这些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返回,应用程序可以完全管理返回目录中的文档。

具体可参考:https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts

比如说,打开联系人列表选择一个联系人的ActivityResultContracts的实现为:

/*** An {@link ActivityResultContract} to request the user to pick a contact from the contacts* app.* <p>* The result is a {@code content:} {@link Uri}.** @see ContactsContract*/public static final class PickContact extends ActivityResultContract<Void, Uri> {@NonNull@Overridepublic Intent createIntent(@NonNull Context context, @Nullable Void input) {return new Intent(Intent.ACTION_PICK).setType(ContactsContract.Contacts.CONTENT_TYPE);}@Nullable@Overridepublic Uri parseResult(int resultCode, @Nullable Intent intent) {if (intent == null || resultCode != Activity.RESULT_OK) return null;return intent.getData();}}

附上一个实例:

private val aLauncher =registerForActivityResult(ActivityResultContracts.PickContact()) { uri: Uri? ->// Handle the returned Uri//crimesuspect启动activity的注册laucherval queryFields = arrayOf(ContactsContract.Contacts.DISPLAY_NAME)val cursor =uri?.let {requireActivity().contentResolver.query(it,queryFields,null,null,null)}cursor?.use {if (it.count > 0) {it.moveToFirst()val suspect = it.getString(0)crime.suspect = suspectcrimeDetailViewModel.saveCrime(crime)binding.crimeSuspect.text = suspect}}}设置监听器的时候:binding.crimeSuspect.setOnClickListener {    aLauncher.launch()}

4.自定义协定

除了上面的预定义协定,我们还可以根据实际的业务定义自己的协定,当然实现也很简单,只需要继承ActivityResultContract<I, O>抽象类即可,ActivityResultContract类有两个抽象方法,

//创建Intent,在Activity#startActivityForResult中使用I input是定义的范型
public abstract Intent createIntent(Context context, I input)
//解析Activity#onActivityResult中的返回结果,返回范型O
public abstract O parseResult(int resultCode, Intent intent)

下面实现一个例子:

// 定义协定
class MyActivityResultContract : ActivityResultContract<Int, String>() {override fun createIntent(context: Context, input: Int?): Intent {return Intent(context, ActivityB::class.java).apply {putExtra("projectId", input)}}override fun parseResult(resultCode: Int, intent: Intent?): String? {if (intent == null || !intent.hasExtra("projectName")) {return null}return intent.getStringExtra("projectName").orEmpty()}
}//注册协定
private val getProject = registerForActivityResult(MyActivityResultContract()) {//it 是返回值
}
//启动页面
getProject.launch(23)

5.非Activity、Fragment页面接收协定结果

一般的onActivityResult只能在Activity类处理返回结果,处理业务逻辑,增加了代码的耦合性,同时有很多场景希望在自己的类里面接收结果,处理逻辑,比如在Adapter里面响应点击事件,处理返回结果,下面介绍如何在业务类实现打开新页面,处理返回结果。

页面的启动管理是通过ActivityResultRegistry实现的,Activity里面已经定义好了ActivityResultRegistry方便我们使用,在自己的类里面只需要传递过来就可以处理跳转逻辑了。

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 : MyLifecycleObserveroverride 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 imageobserver.selectImage()}}
}

使用 ActivityResultRegistry API 时,强烈建议您使用可接受 LifecycleOwner 作为参数的 API,因为 LifecycleOwner 会在 Lifecycle 被销毁时自动移除已注册的启动器。不过,如果 LifecycleOwner 不存在,每个 ActivityResultLauncher 类都允许您手动调用 unregister() 作为替代。

使用registerForActivityResult替代onActivityResult相关推荐

  1. android char 几个字节,Android日常基础知识整理(上)

    1.java char占两个字节 unicode 字符集 不是编码,类似于ASCII码char 不存utf-8,而是存utf-16utf-8 占1~3个字节 字符串长度与字符数不相等 2.java S ...

  2. onActivityResult被标注过时了,新API的写法

    首先添加依赖 implementation 'androidx.activity:activity-ktx:1.3.1'implementation 'androidx.fragment:fragme ...

  3. registerForActivityResult请求权限/拍照/选取视频图片/裁剪图片

    权限相关 //近似定位(模糊定位) Manifest.permission.ACCESS_COARSE_LOCATION //精确定位 Manifest.permission.ACCESS_FINE_ ...

  4. 简单的使用腾讯X5内核浏览器替代Android原生的WebView

    目录 简单的使用腾讯X5内核浏览器替代Android原生的WebView 第一步:X5官网下载SDK,引入到AndroidStudio中 第二步:如果是64位CPU手机,则需要引入一个so(liblb ...

  5. TOF摄像机可以替代Flash激光雷达吗?

    TOF摄像机可以替代Flash激光雷达吗? 一.基于ToF技术的Flash激光雷达 基本成像原理上ToF Camera与LiDAR相同,都采用飞行时间测距技术(包括利用APD或SPAD的直接测距法,和 ...

  6. 查看器_三款完美替代Windows10自带照片查看器的神器!

    Windows10系统中的看图软件Microsoft 照片,被吐槽已经不是一天两天了,2020年马上过完了,我在使用照片功能查看图片时还会出现假死问题. 如果少点bug,说实话Microsoft 照片 ...

  7. 跨平台抓包软件,可以替代Fiddler

    2019独角兽企业重金招聘Python工程师标准>>> Zed Attack Proxy (ZAP) 是个强大的跨平台的抓包工具,可以用来替代windows下的Fiddler htt ...

  8. 7 款可替代 top 命令的工具!(二)

    作者 | JackTian 来源 | 杰哥的IT之旅 上一篇文章中给大家介绍了<11 款可替代 top 命令的工具!>,今天我再来给大家推荐 7 款可替代 top 命令的工具,看完这两篇替 ...

  9. 11 款可替代 top 命令的工具!

    ‍ ‍ 作者 | JackTian 来源 | 杰哥的IT之旅 在 Linux 环境下 top 命令都不陌生,它以实时动态的方式查看系统的整体运行情况,综合了多方信息监测系统性能和运行信息的实用工具,通 ...

最新文章

  1. 死机、蓝屏、系统运行过慢
  2. 排队两小时买墨茉、虎头局,但别指望年轻人“味蕾忠诚”
  3. Cocos creator -引擎解构
  4. delphi5开发人员指南_成为企业家并发挥作用的开发人员指南
  5. 这个时代会残酷惩罚不肯改变的人
  6. win2003负载均衡设置
  7. ubuntu apache fastcgi 虚拟主机安装
  8. ActiveMQ面试题
  9. python读取文件大小、时间_Python从netCDF文件读取数据,时间为测量开始后的“秒数”...
  10. java awt区域,构建Java Swing中的区域图
  11. css.ppt,CSS ppt.ppt
  12. imx226_【索尼IMX136LQJ-C、IMX236LQJ-C、IMX226CQJ-C、IMX274LQC-C、】价格_厂家 - 中国供应商...
  13. html 语音识别输入法,9种外语语音识别 搜狗输入法成国内支持语种最多输入法...
  14. 核壳油溶性CaSe/CdS/ZnS量子点修饰DADA与MPA-CdSe量子点的制备过程
  15. igraph包安装教程
  16. MyApps平台为政企数据保驾护航,筑牢办公安全防线
  17. 动态IP与静态ip的区别是什么
  18. 懒人精灵(一款类似按键精灵的工具)制作和使用C/C++编写的插件
  19. 计算机的哪个盘用来玩游戏,玩游戏的电脑虚拟内存放在哪个盘更好
  20. Splashtop 与 Acronis 集成,提供可扩展的远程支持

热门文章

  1. 服务器运行速度影响哪些因素,影响服务器运行的九大因素
  2. shmmax单位_linux 内存管理——内核的shmall 和shmmax 参数
  3. Android友盟增量更新
  4. oracle 学习笔记之触发器
  5. 看懂SqlServer查询计划
  6. CentOS PPTP ×××
  7. 如何在自己的信息管理系统里集成第三方权限控制组件 - 设计一个漂亮的WEB界面...
  8. 网络字节序,主机字节序,地址转换函数
  9. 动态生成treeview
  10. P1640 [SCOI2010]连续攻击游戏 匈牙利算法