Runtime 运行时模块
viewcompose-runtime 是 ViewCompose 其他模块共同使用的平台无关状态、快照、观察与轻量组合
引擎。当自定义集成只需要 ViewCompose 的状态或组合语义,而不需要 Android View 宿主时,
可以直接使用该模块。
本模块不负责 UI 渲染、Android 生命周期集成、可视帧调度,也不负责跨进程重建的状态持久化。 这些职责属于更上层的模块及其宿主。
产物与稳定性
dependencies {
implementation("com.viewcompose:viewcompose-runtime:0.1.0-alpha03")
}
- 稳定性:Alpha。Alpha 版本之间可能发生源码和二进制不兼容变更。
- 平台:Kotlin/JVM,使用 Java 11 工具链编译;不依赖 Android SDK 或 AndroidX。
- 直接依赖的 ViewCompose 模块:无。
- 传递提供的 ViewCompose 模块:无。
- 公共
snapshotFlowAPI 返回Flow,因此会暴露 Kotlin Coroutines。 - 本版本构建基线:Kotlin 2.0.21。除非选择的其他产物有要求,否则使用者不需要 Android Gradle Plugin。
最小状态示例
val count = mutableStateOf(0)
val label = derivedStateOf { "Count: ${count.value}" }
count.value += 1
check(label.value == "Count: 1")
显式可变快照之外的状态写入会立即提交。需要让多个值原子可见时,应使用事务:
val count = mutableStateOf(0)
val enabled = mutableStateOf(false)
Snapshot.withMutableSnapshot {
count.value = 1
enabled.value = true
}
check(count.value == 1 && enabled.value)
主要 API
State、MutableState与derivedStateOf提供支持快照的值,以及基于读取依赖惰性计算的派生状态。Snapshot与MutableSnapshot提供一致性读取、带冲突报告的原子缓冲写入。RuntimeObservation是把状态读取转化为显式失效订阅的 Q3 API。一次成功的全局 Apply 最多在 Apply 线程调用每个 受影响 Observation 一次,即使多个依赖同时变化;不同 Apply 仍是不同的通知机会。Q3prepareReplacement会通过同一个 Observation Identity 读取候选依赖集合;提交时保留共有订阅 并原子切换,中止时不会扰动已提交依赖集合。snapshotFlow创建 Cold Flow;它会为每个 Collector 跟踪 Snapshot 读取、合并失效、替换条件依赖,并只发出 结构不相等的计算结果。ComposerLite在不依赖编译器生成变更标记的前提下,提供事务式位置组合、remember 值、effect 与诊断。CompositionTimingCollector、CompositionTimingScope与ComposerLite.prepareRootWithTiming组成 Q3、仅请求期有效的组合计时边界。只有实际执行的 Scope 会被提交给 Collector;跳过的 Scope 不调用接口,也不读取时钟。Collector 负责单一 Monotonic Clock、嵌套核算、上限与开销测量;Runtime 提供惰性分配的进程内 Identity 和已经保留的有界 Source Hint。MonotonicFrameClock是动画集成所消费的平台无关计时契约。
完整生成参考位于
viewcompose-runtime API 树。
由于当前版本仍为 Alpha,文档站不会提供稳定的 latest 别名。
状态与生命周期契约
MutableState的等价判断和快照冲突行为由其SnapshotMutationPolicy决定。等价写入不会推进 全局快照,也不会通知读取者。Snapshot在释放前会固定保留历史记录。读取快照不再使用时,必须调用close、dispose或 Kotlinuse。MutableSnapshot应在应用或放弃后释放。冲突失败不会改变目标,可以重试;成功应用是终态。Observation拥有收集期间读取的全部状态订阅。一次成功的全局 Apply 最多使其失效一次, 多个受影响 Observation 按首次观察的稳定顺序交付。不再需要通知时应将其释放,避免状态继续 持有订阅;已经与释放形成竞态并开始的 Callback 可以执行完成。PreparedObservationReplacement是终态对象:外部候选工作成功或失败后,必须且只能调用一次commit或abort。Prepare 会保留已提交订阅,并临时订阅候选独有依赖,避免读取和发布之间 丢失更新或重复 Callback。同一个 Observation 同时只允许一个 Prepared Replacement。- 每个
snapshotFlowCollector 拥有独立的读取观察。取消或计算失败会将其释放;计算必须无 副作用,并且运行次数可能多于发出值的次数。 ComposerLite与派生状态实例按线程封闭设计。宿主负责串行化组合、prepared commit/abort、effect 投递和释放。- Composition Timing Collector 只在一次同步
prepareRootWithTiming调用期间有效。它不得保留 Scope、调用应用代码、阻塞、执行 I/O 或重入 Composer;Collector 失败与组合隔离。普通prepareRoot路径不分配 Timing Identity、不执行逐 Scope 时钟读取,也不保留 Timing History。 - Remembered 生命周期对象会保持 Pending,直到
onRemembered成功返回。激活抛错后,后续 成功的 Composition Commit 会重试它,但不会再次激活已成功的兄弟对象。激活前移除会调用onAbandoned;Active 值则通过恰好一次onForgotten终止。Abort 不会终止已提交对象,也 不会激活候选替换对象。 ComposerLite.composeRoot会提交 Runtime State,但不会执行一次性 Side Effect。宿主只有在 对应渲染树与 Remember 生命周期事务都提交成功后,才调用commitSideEffects。ComposerLite.rememberUpdatedState仅向活跃组合线程暴露候选值,在已提交生命周期回调前 发布该值,并在 Abort 时丢弃它。ComposerLite.scopedExplicitSaveableKey根据当前结构 Key 路径派生显式rememberSaveableRegistry Key。Lazy List、Pager 等子 Session 所有者通过此边界隔离恢复 状态,因此不同逻辑条目中相同的应用 Key 不会共享状态,物理 Holder 变化也不会改变逻辑所有者。 若两个不相等的活跃 Keyed Group 产生相同结构路径 Hash,Runtime 会在注册 Saveable Provider 前失败,而不会共享恢复状态;因此自定义 Saveable Key 必须提供稳定且无碰撞的 Hash。- 显式 Keyed Sibling Group 可以移动,同时完整保留 Scope Identity,包括 Remember Slot、 Observation、Child 与 Saveable Path。同一 Parent 下重复的有效 Key/Signature 会让组合尝试 失败,防止两个逻辑条目共享状态。
- Callback 失败会保留原始 Throwable,并附加有界 Effect Kind、Operation、结构 Scope、Slot
与不持有 Key 对象的 Metadata。Host 可以通过
ComposerLite构造参数选择非负的同步 Callback 警告阈值。
长期持有旧快照会保留额外的值记录,频繁改变结构组顺序会阻止组合复用。这些操作也不会阻止 任意用户计算;调用方应把昂贵工作移出状态访问器与组合块,或显式缓存结果。
相关文档
Android 应用通常通过 viewcompose-ui-foundation 或 viewcompose-host-android 传递使用本产物。
只有在自身公共 API 暴露其类型,或者开发自定义宿主/运行时集成时,才需要显式依赖。
兼容性说明
0.1.0-alpha02 首次建立快照和轻量组合契约,没有更早的稳定版本迁移路径。不要把内部快照
标识符、组合 saveable key、诊断结构或实现类名持久化为长期外部数据;只有公共 API 参考明确
描述的行为属于受支持契约。
本版本新增 snapshotFlow,并因此把 Kotlin Coroutines 暴露为 API 依赖;同时移除 Alpha 阶段的
ComposerLite.disposableEffect Slot API。自定义组合集成应把所有权工作迁移到 Remembered
RememberObserver,应用 UI 则使用 viewcompose-ui-foundation 的 Effect API。Prepared
Composition 现在强制执行 Owner Thread、终态释放与 Callback Re-entry 边界。Remember 激活失败
可重试;显式 Keyed Sibling 会作为完整 Scope 移动,重复有效身份则快速失败。