一、 痛点:Compose 页面回传数据的"姿势"对了吗?
在 Jetpack Compose 的原生导航(Navigation)中,如果你想在页面 A 打开页面 B,并在 B 关闭时带回一个结果,你通常会怎么做?
目前的常见方案:
- NavBackStackEntry 方案 :操作
previousBackStackEntry.savedStateHandle。代码极其冗长,且需要手动观察LiveData,在DisposableEffect中销毁,稍不留神就容易写出内存泄漏或不响应的代码。 - 全局单例/共享 ViewModel :虽然简单,但对于这种"一次性"或"跨页面"的简单回传来说太重了,且对 Process Death(进程重启) 的状态恢复支持往往需要额外处理。
难道就没有一种既能像 Compose State 一样响应式 ,又能自动处理状态恢复 ,且代码量极简的方案吗?
ComposeResult 应运而生。它是一个专为 Jetpack Compose 打造的轻量级、响应式页面通信库。
二、 核心初体验:3 分钟集成
ComposeResult 最大的特点是:像使用本地 State 一样处理跨页面通讯。
1. 添加依赖 (build.gradle.kts)
Kotlin
scss
dependencies {
implementation("io.github.lans:compose-result:1.1.2")
}
2. 声明 Provider
在你的导航根目录或 Activity 最外层包裹 ResultStoreProvider,它会自动构建一个持久化的数据中心。
Kotlin
scss
ResultStoreProvider {
// 你的 NavHost 或其他导航逻辑
MainAppNavHost()
}
3. 页面 B:设置结果并返回
Kotlin
ini
val store = LocalResultStore.current
Button(onClick = {
// 设置结果,tag 用于标识唯一通信
store.setResult("Hello From B!", tag = "key_msg")
navController.popBackStack()
}) { Text("返回数据") }
4. 页面 A:自动响应数据
Kotlin
kotlin
val store = LocalResultStore.current
// 重点:这里是响应式的,一旦 B 设置了值,A 会自动重组 UI
val result by store.getResultAsState<String>(tag = "key_msg")
Text("收到结果: ${result ?: "等待中"}")
三、 为什么它更好用?(对比分析)
| 维度 | 原生 SavedStateHandle | ComposeResult |
|---|---|---|
| 代码量 | 繁琐,需手动操作 BackStackEntry | 极简 (LocalStore 直接操作) |
| UI 刷新 | 需配合 LiveData/Flow 转 State | 原生 State 支持,自动重组 |
| 进程重启 | 支持 (依赖 Bundle) | 天然支持 (绑定 SaveableRegistry) |
| 架构解耦 | 与 Navigation 方案强耦合 | 全架构支持 (Nav 2.x, 3.0 或自定义) |
四、 进阶:Hilt 与全链路响应式
在复杂的业务场景下,我们可能需要在 ViewModel 中监听数据变动。ComposeResult 配合 snapshotFlow 可以轻松实现业务逻辑层与 UI 层的无感联动。
1. 注入配置
在 Hilt Module 中将 ResultStore 声明为单例:
Kotlin
less
@Provides
@Singleton
fun provideResultStore(): ResultStore = ResultStore()
2. ViewModel 层监听
利用 snapshotFlow 监听全局存储的变动,实现埋点、数据库同步等副作用:
Kotlin
less
@HiltViewModel
class HomeViewModel @Inject constructor(
private val resultStore: ResultStore
) : ViewModel() {
init {
snapshotFlow { resultStore.allResults().toMap() }
.filter { resultStore.hasTag<String>("user_name") }
.onEach {
val name = resultStore.getResult<String>("user_name")
// 处理业务逻辑,如上报事件
reportEvent(name)
}
.launchIn(viewModelScope)
}
}
五、 技术原理揭秘
ComposeResult 在 Composition 树的根部构建了一个持久化的存储空间。其核心在于:
- CompositionLocal :让
ResultStore在 Compose 树中透明传递,无需一层层传参。 - rememberSaveable :数据会自动挂载到 Android 系统的
SaveableStateRegistry。 这意味着:即使 App 进程被系统回收,数据也能在重启后自动通过 Bundle 恢复。 - MutableStateMap:确保了数据变更时,所有订阅了该 tag 的 Composable 都能精准重组,实现真正的响应式。
六、 注意事项与建议
- Tag 唯一性 :建议定义常量管理
tag,避免不同业务冲突。 - 数据大小 :由于底层依赖 Bundle 机制,请勿传递过大的 Bitmap 或海量列表,建议回传 ID 或实现
Parcelable的 Model。 - 灵活消费 :库支持
getResultAsState(持续观察)和consumeResult(阅后即焚)两种模式。
结语
ComposeResult 的初衷是让 Compose 页面通信回归本质------简单、响应式、可靠 。如果你也受够了手动管理 SavedStateHandle 的痛苦,不妨尝试一下。
🚀 GitHub 传送门 :github.com/lans/compos...
📦 最新版本 :1.1.2
如果你觉得这个库有帮助,欢迎在 GitHub 点个 Star 🌟,评论区分享你在 Compose 开发中遇到的通信痛点!