【Jetpack】学穿:Activity Results API_requestmultiplepermissions

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新HarmonyOS鸿蒙全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img

img
img
htt

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上鸿蒙开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注鸿蒙)
img

正文

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)
}
}

③ ActivityResultCallback → 结果回调

第二个入参,见名知意:启动Activity并返回当前Activity时的 结果回调

就定义了一个回调方法,Activity Result API 又是 模版方法模式 封装的思想体现,开发仔按需注入 协定类型结果回调 即可,无需关注底层细节。巴适得很!

杰哥当然不会止步于调别人写好的API,接着再探一波更深层次的原理,弄清楚整条调用链路。


0x2、原理再探

在Activity、Fragment中可以直接使用 registerForActivityResult(),是因为 ComponentActivityFragment 都实现了 ActivityResultCaller 接口。

① Activity

先跟下 ComponentActivity#registerForActivityResult()

第一个参数构造了一个key,规则:activity_rq# + 一个自增的AtomicInteger值,怪不得不用另外定义一个REQUEST_CODE,就能进行区分。

继续跟 ActivityResultRegistry#register()

看着好像挺复杂,其实不然,核心就是:

添加了一个观察者,当生命周期组件(传入的第2个参数) 状态切换到 ON_START 时执行回调

然后下半段返回了一个 ActivityResultLauncher 实例:

跟下 onLaunch() 发现是一个抽象方法,具体实现在 ComponentActivity 中:

到此,基本的调用链条就浮出水面了:

  • ComponentActivity 内部初始化了一个 ActivityResultRegistry 实例,并重写了 onLaunch()
  • ② 开发者调用 registerForActivityResult() 最终调用 ActivityResultRegistry.register(),在此添加了一个观察者,当生命周期状态切换到ON_START时,执行协定 Contract.parseResult() 生成输出内容,并把结果作为参数传入回调 callback.onActivityResult() 中。
  • ③ 注意!②是要生命周期发生改变才会触发的,开发者要调用 ActivityResultLauncher.launch() 才会发起跳转,其中回调了 onLaunch() 方法,在此调用了协定 Contract.createIntent() 返回一个和 startActivityForResult() 搭配使用的 Intent 实例。
  • ④ 跳转目标Activity后返回此页面,生命周期发生改变,然后回调②中的相关代码。

描述起来好像有点拗口,不过你自己照着跟下源码就清楚了,接着跟下Fragment~

② Fragment

同样跟下 registerForActivityResult()

最终调用 prepareCallInternal()

思路也很简单,想办法拿到 宿主Activity中的ActivityResultRegistry实例,调它的 register() 拿到返回的 ActivityResultLauncher实例引用。最后返回 新的ActivityResultLauncher 实例,在launch()中调用前面那个Activity的 ActivityResultLauncher实例引用 的launch()方法。TM调的是Activity的launch(),这一手 委托代理 玩挺6啊。

对了,这有个小细节,生命周期组件传入的是 Fragment.this,所以不用担心Fragment销毁没解绑导致的内存泄露问题。

③ 非Activity/Fragment 接收Activity结果

实现一个 LifecycleObserver 用于处理协定的注册和启动器的启动,代码示例如下:

调用处:

④ 亿点小细节:配置改变引起Activity重建的处理

ActivityResultRegistry 中还发现了介个:

好家伙,连配置更改导致重建的场景也考虑到了吗?

保存了:key(requestCode)相关的数据、处理结果、Random随机数实例。

requestCode和Result得以保留,Activity重建后,再把它们分发给新注册的Callback,避免了数据的丢失。

⑤ 亿点补充:测试Activity结果调用

默认情况下,registerForActivityResult() 会自动使用Activity提供的 ActivityResultRegistry,而它还提供了一个重载,支持传入自己的 ActivityResultRegistry 实例。能干嘛?拦截结果调用进行测试啊,不会另外启动另一个Activity。代码示例如下:


0x3、关于封装

Activity Results API 了解得七七八八了,接下来可以放心地用到项目中了,虽然它的API已经很简单易用了。但对于 喜欢偷懒到极致的开发仔 来说还是不够的,可以利用Kotlin相关的语法特性,封装下再少写一些代码。

捋下API使用链条:

  • registerForActivityResult()ActivityResultLauncher,需在ON_START或之前注册,在OnCreate()时再初始化会报错,还得传入一个**ActivityResultContract** 实例,最后跟一个 ActivityResultCallback 回调。
  • 调用 ActivityResultLauncher#launch() 才触发页面跳转,需要传入一个输入(如Intent)实例。

最简单的封装就是写几个 扩展方法,从ActivityResultLauncher生成和launch()调用处入手:

// 扩展
fun ComponentActivity.registerActResult(callback: ActivityResultCallback) =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
callback.onActivityResult(it) }

fun Fragment.registerActResult(callback: ActivityResultCallback) =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
callback.onActivityResult(it) }

fun Intent.launch(launcher: ActivityResultLauncher) {
launcher.launch(this)
}

// 注册处
private val mLauncher = registerActResult {
shortToast(“收到测试数据:${it.data?.getStringExtra(“value”)}”)
}

// 调用处
Intent(this, SecondActivity::class.java).launch(mLauncher)

还可以在优化下,比如改成基于 ActivityResultCaller 进行扩展,然后把常用的一些跳转,如权限、打开相机、录像等写成一个个扩展函数,用的时候直接调用即可。懒得自己写或者想找参考的可以看看 → ActivityResult.kt

如果想代码写得更少更优雅,可以折腾得更复杂些,比如结合生命周期回调,各种简化调用的扩展,甚至弄成DSL调用等,具体可以参考这些:

怎么封装看自己,觉得适合就行,笔者就懒得整那么复杂了~


0x4、小结

借着重构BaseFragment的机缘巧合,过了波Activity Results API的用法,阅读源码了解到背后的实现原理,小试了一下封装。心里有底了,赶紧在重构项目的时候安排上!!!

有问题或者建议欢迎在评论区提出,肝文不易,如果本文有帮到你的话,可以给个三连,谢谢~


参考文献

文末

我总结了一些Android核心知识点,以及一些最新的大厂面试题、知识脑图和视频资料解析。

需要的小伙伴直接扫描下方二维码免费领取哦,以后的路也希望我们能一起走下去。(谢谢大家一直以来的支持,需要的自己领取)

请添加图片描述

Android学习PDF+架构视频+面试文档+源码笔记

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

78272f471972.png)

Android学习PDF+架构视频+面试文档+源码笔记

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注鸿蒙)
[外链图片转存中…(img-0HeCkPsQ-1713345139763)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 27
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值