别再手动管理 NavBackStackEntry 了!ComposeResult:更优雅的 Jetpack Compose 页面通信方案

一、 痛点:Compose 页面回传数据的"姿势"对了吗?

在 Jetpack Compose 的原生导航(Navigation)中,如果你想在页面 A 打开页面 B,并在 B 关闭时带回一个结果,你通常会怎么做?

目前的常见方案:

  1. NavBackStackEntry 方案 :操作 previousBackStackEntry.savedStateHandle。代码极其冗长,且需要手动观察 LiveData,在 DisposableEffect 中销毁,稍不留神就容易写出内存泄漏或不响应的代码。
  2. 全局单例/共享 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 树的根部构建了一个持久化的存储空间。其核心在于:

  1. CompositionLocal :让 ResultStore 在 Compose 树中透明传递,无需一层层传参。
  2. rememberSaveable :数据会自动挂载到 Android 系统的 SaveableStateRegistry。 这意味着:即使 App 进程被系统回收,数据也能在重启后自动通过 Bundle 恢复。
  3. 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 开发中遇到的通信痛点!

相关推荐
小嘿前端仔1 天前
用AI读源码这件事:前端视角的实战方法论,附Vue3 reactivity源码解读示范
前端
其实防守也摸鱼1 天前
XSS漏洞全景解析:从原理、实战利用到纵深防御
前端·网络·安全·xss·xss漏洞
戴维南1 天前
DeepAgents 快速上手教程
前端
bigfatDone1 天前
OpenSpec + Superpowers 联合开发工作流
前端
北漂大橙子1 天前
OpenSpec 完全指南:让 AI 编码可预测的规范框架
前端
lemon_yyds1 天前
OpenCode 最佳实践
前端
用户52709648744901 天前
前端登录菜单加载性能优化总结
前端
你觉得脆皮鸡好吃吗1 天前
Check Anti-CSRF Token (AI)
前端·网络·网络协议·安全·csrf·网络安全学习
一个快乐的咸鱼1 天前
nextjs接入AI实现流式输出
前端