挑两个协议看看具体代码实现,先是 StartActivityForResult
:
返回类型ActivityResult实现了Parcelable序列化接口,定义了需要用到的两个字段:mResultCode 和 mData。
接着是 TakePicturePreview
:
所以 ActivityResultContract
中的函数意义分别是:
createIntent
(context: Context, input: I): Intent → 创建用于startActivityForResult
的intent对象;parseResult
(resultCode: Int, intent: Intent?): O → 对onActivityResult
的结果进行转换;getSynchronousResult()
→ 可选,处理一些不需要启动Activity就能知道预期结果的场景,如RequestPermission会用到;
了解函数意义后,如果你觉得内置协定满足不了你,完全可以自定义一波,官方示例如下:
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()
,是因为 ComponentActivity
和 Fragment
都实现了 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~