RememberObserver
实现该接口的对象可以监听它 在 Composition 中 的状态。
interface RememberObserver {
//对象保存到组合时触发
//实现接口的对象被保存到 Composition.slotTable 中
fun onRemembered()
//对象从组合中移除时触发
//实现接口的对象从 Composition.slotTable 删除
fun onForgotten()
//对象保存到组合没有成功时触发
fun onAbandoned()
}
使用 RememberObserver 接口需要注意两点
- 在对应的回调中编写逻辑
- 将对象写入到 Composition.slotTable 中 ( 接口就是用于监听对象在不在 Composition.slotTable 中的 )
除了上一章 buildContext() 内部创建的 CompositionContextHolder ,Effects Api 协程启动/取消也是使用 RememberObserver 接口实现的。
我们拿 LaunchedEffect 举例,在此之前先看一下 remember() 方法
remember() 方法
将参数 calculation 计算结果保存到当前 Composition.slotTable 中,所以 remember() 是实现 RememberObserver 接口对象写入 Composition.slotTable 的一种方式。
碰到了,又不难 ,当然要重拳出击。
@Composable
inline fun <T> remember(crossinline calculation: @DisallowComposableCalls () -> T): T =
currentComposer.cache(false, calculation)
@Composable
inline fun <T> remember(
key1: Any?,
crossinline calculation: @DisallowComposableCalls () -> T
): T {
return currentComposer.cache(currentComposer.changed(key1), calculation)
}
remember 方法 key 参数用来产生判断当前保存的值是否失效的 invalid,calculation 参数用来产生需要保存的具体值,方法具体逻辑在 currentComposer.cache() 中。
remember 方法干了两件事 :①判断保存的值是否失效 ;②传递参数给 currentComposer.cache()
@ComposeCompilerApi
inline fun <T> Composer.cache(invalid: Boolean, block: @DisallowComposableCalls () -> T): T {
@Suppress("UNCHECKED_CAST")
return rememberedValue().let {
//如果保存的值失效 或者 第一次保存
if (invalid || it === Composer.Empty) {
//执行 calculation 代码块
val value = block()
//将计算结构保存到 slotTable 中
updateRememberedValue(value)
value
} else it
} as T
}
internal class ComposerImpl(){
//如果是插入操作 返回 Composer.Empty,否则返回 slotTable 保存的值
override fun rememberedValue(): Any? = nextSlot()
//updateValue() 细节稍后介绍
override fun updateRememberedValue(value: Any?) = updateValue(value)
@PublishedApi
@OptIn(InternalComposeApi::class)
internal fun nextSlot(): Any? = if (inserting) {
validateNodeNotExpected()
Composer.Empty
} else reader.next().let { if (reusing) Composer.Empty else it }
}
只有在 invalid 为 true —— remember() 方法中通过 key 判断当前保存的值失效,和第一次保存的时候会执行 calculation 代码块并将结构保存/更新到 slotTable 中。
LaunchedEffect() 方法
@Composable
@NonRestartableComposable
@OptIn(InternalComposeApi::class)
fun LaunchedEffect(
key1: Any?,
block: suspend CoroutineScope.() -> Unit
) {
val applyContext = currentComposer.applyCoroutineContext
remember(key1) { LaunchedEffectImpl(applyContext, block) }
}
方法实现出奇的简单
- 拿到 Recomposer 提供的 CoroutineContext (前面 19.2 分析过了)
- 使用 remember() 向 SlotTable 中插入一个 LaunchedEffectImpl 对象
internal class LaunchedEffectImpl(
parentCoroutineContext: CoroutineContext,
private val task: suspend CoroutineScope.() -> Unit
) : RememberObserver {
private val scope = CoroutineScope(parentCoroutineContext)
private var job: Job? = null
override fun onRemembered() {
job?.cancel("Old job was still running!")
job = scope.launch(block = task)
}
override fun onForgotten() {
job?.cancel()
job = null
}
override fun onAbandoned() {
job?.cancel()
job = null
}
}
DisposableEffect() 、rememberCoroutineScope() 也是用这种 remember { RememberObserver } 方式实现的,
CompositionContextHolder 在 composerImpl.buildContext() 方法中直接调用 composerImpl.updateValue() 保存到了 Composition.slotTable 中。
LaunchedEffectImpl 实现 RememberObserver 接口,LaunchedEffectImpl 对象保存到 Composition.slotTable 时开启协程执行 block ,在 LaunchedEffectImpl 对象从 Composition.slotTable 中删除时取消协程。
RememberObserver 工作原理
RememberObserver 接口中的回调是如何触发的呢?
Composer 的特殊处理
ComposerImpl updateValue 方法在插入/更新 SlotTable 时会对实现了 RememberObserver 接口的对象进行特殊处理
@PublishedApi
@OptIn(InternalComposeApi::class)
internal fun updateValue(value: Any?) {
if (inserting) { //插入
writer.update(value)//将 value 写入 slotTable
//如果 value 实现了 RememberObserver 接口
if (value is RememberObserver) {
//record() 向 changes 列表添加一个 Change {}
//Change 执行调用 rememberManager.remembering(value)
record { _, _, rememberManager -> rememberManager.remembering(value) }
//将 value 添加到 abandonSet
abandonSet.add(value)
}
} else { //更新
val groupSlotIndex = reader.groupSlotIndex - 1
//将 value 添加到 abandonSet
if (value is RememberObserver) {
abandonSet.add(value)
}
//recordSlotTableOperation 向 changes 列表添加一个 Change {}
recordSlotTableOperation(forParent = true) { _, slots, rememberManager ->
//如果 value 实现了 RememberObserver 接口
//调用 rememberManager.remembering(value)
if (value is RememberObserver) {
rememberManager.remembering(value)
}
// slots.set 将 value 值保存到 groupSlotIndex
// 并返回 groupSlotIndex 之前保存的值 previous
when (val previous = slots.set(groupSlotIndex, value)) {
//如果从 slotTable 删除的 previous 实现了 RememberObserver
//调用 rememberManager.forgetting(previous)
is RememberObserver ->
rememberManager.forgetting(previous)
//如果 previous 是 RecomposeScopeImpl 类型
//previous.release()
is RecomposeScopeImpl -> {
val composition = previous.composition
if (composition != null) {
previous.release()
composition.pendingInvalidScopes = true
}
}
}
}
}
}
Composer 向 SlotTable 插入/更新实现了 RememberObserver 接口的 value 时都会做两个操作
- 将要插入 SlotTable 的 value 添加到 abandonSet
- 创建一个 Change 并将 这个 Change 添加到 changes 中,Change 执行时都会调用 rememberManager.remembering( value )
更新操作中如果被替换的对象 previous 也实现了 RememberObserver 接口,还会执行 rememberManager.forgetting( previous )
RememberObserver 回调这时候并没有触发。 只是使用了 abandonSet / changes / rememberManager 对 RememberObserver 处理。
Composition 我们逃课了 T_T 现在开始补课
abandonSet 、changes 和 ComposerImpl 一样是 CompositionImpl 中的属性,同时 abandonSet 、changes 也作为构造参数传递给 ComposerImpl ,也就是说 CompositionImpl 和 ComposerImpl 中使用的 abandonSet 和 changes 是相同的。
internal class CompositionImpl() : ControlledComposition {
private val abandonSet = HashSet<RememberObserver>()
private val changes = mutableListOf<Change>()
private val composer: ComposerImpl =
ComposerImpl(
applier = applier,
parentContext = parent,
slotTable = slotTable,
abandonSet = abandonSet,
changes = changes,
lateChanges = lateChanges,
composition = this
).also {
parent.registerComposer(it)
}
}
abandonSet
abandonSet 所有添加到 SlotTable 中的 RememberObserver 都会被存入这个集合。每一个 RememberObserver 都可能被废弃。
在 CompositionImpl.applyChanges() 阶段 abandonSet 会作为构造参数生成 RememberEventDispatcher
changes
changes 在 Composition 中是跟 slotTable 同样重要的属性。
如果说 slotTable 代表当前 UI 的状态,那么更新 UI 的操作就是对比当前的状态需要做哪些改变,每一个改变就是一个 Change 。
那么重组就可以理解成 解析需要重组的 @Composable 函数与 slotTable 中保存的状态做对比,需要变的地方记录成 一个 Change 保存到 changes 中,在 CompositionImpl.applyChanges() 阶段统一执行每一个 Change 来更新 UI 状态。
Change 是函数类型起的别名,重组流程还没有看透,这章我们只看如何操作 RememberObserver
internal typealias Change = (
applier: Applier<*>, //操作 LayoutNode
slots: SlotWriter, //操作 SlotTable
rememberManager: RememberManager //操作 RememberObserver
) -> Unit
RememberManager
RememberManager 接口的实现类为 RememberEventDispatcher
private class RememberEventDispatcher(
private val abandoning: MutableSet<RememberObserver>
) : RememberManager {
private val remembering = mutableListOf<RememberObserver>()
private val forgetting = mutableListOf<RememberObserver>()
private val sideEffects = mutableListOf<() -> Unit>()
override fun remembering(instance: RememberObserver) {
forgetting.lastIndexOf(instance).let { index ->
if (index >= 0) {
forgetting.removeAt(index)
abandoning.remove(instance)
} else {
remembering.add(instance)
}
}
}
override fun forgetting(instance: RememberObserver) {
remembering.lastIndexOf(instance).let { index ->
if (index >= 0) {
remembering.removeAt(index)
abandoning.remove(instance)
} else {
forgetting.add(instance)
}
}
}
override fun sideEffect(effect: () -> Unit) {
sideEffects += effect
}
fun dispatchRememberObservers() {
// Send forgets
if (forgetting.isNotEmpty()) {
trace("Compose:onForgotten") {
for (i in forgetting.size - 1 downTo 0) {
val instance = forgetting[i]
if (instance !in abandoning) {
instance.onForgotten()
}
}
}
}
// Send remembers
if (remembering.isNotEmpty()) {
trace("Compose:onRemembered") {
remembering.fastForEach { instance ->
abandoning.remove(instance)
instance.onRemembered()
}
}
}
}
fun dispatchSideEffects() {
if (sideEffects.isNotEmpty()) {
trace("Compose:sideeffects") {
sideEffects.fastForEach { sideEffect ->
sideEffect()
}
sideEffects.clear()
}
}
}
fun dispatchAbandons() {
if (abandoning.isNotEmpty()) {
trace("Compose:abandons") {
val iterator = abandoning.iterator()
while (iterator.hasNext()) {
val instance = iterator.next()
iterator.remove()
instance.onAbandoned()
}
}
}
}
}
}
它有两个作用:
1 管理以 abandoning 为基础的 RememberObserver
remembering()、forgetting() 执行时会以 abandoing 为基础向 remembering 、forgetting 集合中添加 RememberObserver。
需要执行 onRemembered() 的 RememberObserver 被添加到 remembering
需要执行 onForgotten() 的 RememberObserver 被添加到 forgetting
最后被留在 abandoning 中的 RememberObserver 就是需要执行 onAbandoned() 的 RememberObserver
dispatchRememberObservers() 会触发 remembering 中所有 RememberObserver.onRemembered() 和 forgetting 中所有 RememberObserver.onForgotten()
dispatchAbandons() 会触发 abandoning 中所有 RememberObserver.onAbandoned()
2 管理组合中的 SideEffect
遇到简单的重拳出击
SideEffect 每次都会被运行所以解析到 SideEffect 时直接将 SideEffect 记录成了一个 Change 添加到 changes 中
@Composable
@NonRestartableComposable
@OptIn(InternalComposeApi::class)
fun SideEffect(
effect: () -> Unit
) {
currentComposer.recordSideEffect(effect)
}
//--------------
override fun recordSideEffect(effect: () -> Unit) {
//Change 执行时 将 effect 保存到 RememberEventDispatcher.sideEffects 中
record { _, _, rememberManager -> rememberManager.sideEffect(effect) }
}
dispatchSideEffects() 执行 sideEffects 中保存的所有 effect。
CompositionImpl.applyChanges()
事情还是要从初始组合说起 ,我们之前只分析到 composition.composeContent(content) 解析 @Composable 函数,现在我们知道函数中还有一部分代码在 ComposerImpl.updateValue() 时被解析成了 Change 保存到了 changes 中,所以初始组合最后会执行 composition.applyChanges()。
internal override fun composeInitial(
composition: ControlledComposition,
content: @Composable () -> Unit
) {
val composerWasComposing = composition.isComposing
try {
composing(composition, null) {
composition.composeContent(content)
}
} catch (e: Exception) {
processCompositionError(e, composition, recoverable = true)
return
}
//...
try {
composition.applyChanges()
composition.applyLateChanges()
} catch (e: Exception) {
processCompositionError(e)
return
}
}
composition.applyChanges() 会调用 applyChangesInLocked() 来执行 changes 集合中所有的 Change 函数,我们只看 RememberObserver 相关的逻辑。
private fun applyChangesInLocked(changes: MutableList<Change>) {
// RememberEventDispatcher 实现 RememberManager 接口
val manager = RememberEventDispatcher(abandonSet)
try {
if (changes.isEmpty()) return
trace("Compose:applyChanges") {
applier.onBeginChanges()
// Apply all changes
slotTable.write { slots ->
val applier = applier
changes.fastForEach { change ->
//执行 updateValue() 时添加的 Change
//rememberManager.remembering(value)
change(applier, slots, manager)
}
changes.clear()
}
applier.onEndChanges()
}
//触发 onRemembered() onForgotten()
manager.dispatchRememberObservers()
//执行 RememberEventDispatcher.sideEffects 中所有的 effect
manager.dispatchSideEffects()
if (pendingInvalidScopes) {
trace("Compose:unobserve") {
pendingInvalidScopes = false
observations.removeValueIf { scope -> !scope.valid }
cleanUpDerivedStateObservations()
}
}
} finally {
//如果所有的 Change 都被执行完了
//且 RememberEventDispatcher.abandoning 不为空
//RememberEventDispatcher.abandoning 集合中所有的 RememberObserver
//执行 RememberObserver.onAbandoned()
if (this.lateChanges.isEmpty())
manager.dispatchAbandons()
}
}
applyChanges 阶段结束进入 slotTable 的 RememberOserver 触发 onRemembered() , 从 slotTable 中删除的 RememberOserver 触发 onForgotten(),仍然保存 abandonSet 在中的 RememberOserver 触发 onAbandoned()
applyChanges 阶段结束 changes 和 abandonSet 都被清空,初始组合/重组执行完毕 ^_^