AndroidX 将引入有全新 AppState ,用于管理 Compose 状态

最近 AndroidX 给「跨组件 Compose 状态托管场景」引入了 AppState ,目前还没完全落地,但是从代码骨架可以看出来,AppState 的核心目的是:

把 Compose 的可观察状态从某个 「Composable/组件生命周期」里提出来,然后放到更上层的状态容器里管理

这次新增的是 androidx.appstate 包,对应的核心目前有三个公开类型:

r 复制代码
AppState
AppStateKey<T>
AppStateToken

而对应的公开方法包括:

kotlin 复制代码
class AppState {
    fun <T> getState(stateKey: AppStateKey<T>, defaultValue: T): State<T>
    fun <T> setState(stateKey: AppStateKey<T>, value: T)
    fun <T> updateState(stateKey: AppStateKey<T>, defaultValue: T, update: (T) -> T)
    fun addAppStateListener(...): AppStateToken
    fun removeAppStateListener(token: AppStateToken)
}

另外提交里也说了:Added new library to help support hoisting of Compose state ,也就是 AppState 不是用来「替代 ViewModel 」,也不是说「提供完整架构层状态管理 」,而是 help support hoisting of Compose state

那为什么需要 AppState?首先我们知道,Compose 原本的状态模型大概是这样的流程:

因为 Compose 是声明式 UI,而 UI 是状态的表现,所以 MutableState.value 发声改变,会触发读取它的 composable 重组。

但问题在于状态放在哪里:

remember 存在 Composition ,而如果调用它的 composable 被移除后会丢失,而 rememberSaveable 主要是帮助状态跨重组、Activity recreation、系统发起的进程恢复等场景。

所以针对这个场景,AppState 的注释也是说了:

vbnet 复制代码
Class that contains a store that maintains compose state beyond individual Android components.
​
There is no limitation on where these instance should be instantiated as that is left up to the developer.

也就是它不是把状态绑定到某个 Activity、Fragment、NavBackStackEntry 或者单个 Composable,而是让你自己决定 AppState 实例的作用域,换句话说:

Compose runtime 的 State<T> / MutableState<T> 还是是底层可观察状态模型,但状态容器不再一定活在某个 Composable 里,而是可以被提升到更外层。

所以实际上 AppState 就是一个 keyed MutableState store ,这次源码里最核心的就是这两个 map:

swift 复制代码
private val stateStore: MutableMap<AppStateKey<*>, MutableState<*>> = mutableMapOf()
​
private val appStateListeners = mutableMapOf<AppStateToken, CoroutineScope>()

第一个 stateStore 是真正存状态的地方,第二个 appStateListeners 是给未来监听器准备的 token 到 coroutine scope 映射:

实际上这里的重要点是:

  • AppState 存的不是普通值,而是 MutableState<*>,也就是说它不是一个传统 Map<Key, Value>,而是一个 Compose runtime 可观察状态仓库
  • 外部 getState() 返回的是 State<T>,不是 MutableState<T>
kotlin 复制代码
public fun <T> getState(stateKey: AppStateKey<T>, defaultValue: T): State<T> {
    @Suppress("UNCHECKED_CAST")
    return stateStore.getOrPut(stateKey) { mutableStateOf(defaultValue) } as MutableState<T>
}

这意味着在 API 设计上倾向于:

也就是读写分离: 读的时候拿 State,写的时候走 AppState 的 set/update API。

而对于 getState 用的是 lazy 创建 State ,getState() 的逻辑很简单:

scss 复制代码
stateStore.getOrPut(stateKey) { mutableStateOf(defaultValue) }

也就是它不是每次都拿值,而是拿同一个 MutableState 对象,只要 AppState 实例还活着,对应 key 的 state 就还在

从这里也能看出它和普通 remember { mutableStateOf() } 的不同:

remember 的生命周期跟 Composition 位置绑定,而 AppState 的生命周期跟 AppState 实例本身绑定。

setState 第一次设置时可能注册会 auto-clear listener,其实 setState() 也是这个库目前最有意思的地方:

less 复制代码
public fun <T> setState(stateKey: AppStateKey<T>, value: T) {
    if (!stateStore.contains(stateKey) && stateKey.autoClearKey != null) {
        addAppStateListener { map ->
            val key = stateKey.autoClearKey
            val currentValue = map[key]?.value
            val initialValue = remember { currentValue }
            if (currentValue != initialValue && stateKey.predicate(this@AppState)) {
                LaunchedEffect(currentValue) {
                    stateStore.remove(stateKey)
                    removeAppStateListener(this@addAppStateListener)
                }
            }
        }
    }
    (getState(stateKey, value) as MutableState<T>).value = value
}

也就是 AppStateKey 不只是一个普通 key,它还能定义「什么时候这个状态应该被自动清理」。

另外,对应的 updateState 方法看起来是典型 reducer 风格:

kotlin 复制代码
public fun <T> updateState(
    stateKey: AppStateKey<T>,
    defaultValue: T,
    update: (T) -> T
) {
    val currentState = getState(stateKey, defaultValue)
    setState(stateKey, update(currentState.value))
}

这个 API 设计很像 reducer :

javascript 复制代码
appState.updateState(IntKey, 0) { it + 1 }

按照目前的代码来看, 这个库目前能确定能做的大概类似:

ini 复制代码
val appState = AppState()
​
@Serializable
object NameKey : AppStateKey<String>()
​
val state = appState.getState(NameKey, "default")
// state.value == "default"
​
appState.setState(NameKey, "Asher")
// 再 getState(NameKey, "default").value == "Asher"

另外这个库是 Kotlin consumers only ,属于高度 Kotlin/Compose 化,使用了大量 @Composable lambda、泛型 key、Kotlin serialization、object singleton key 等:

swift 复制代码
AppStateKey<T>
listener: @Composable AppStateToken.(Map<AppStateKey<*>, State<*>>) -> Unit
update: (T) -> T
@Serializable object Key : AppStateKey<String>()

当然,最重要的是,这次修改不只是 Android API ,还有 native bcv

yaml 复制代码
Targets: [iosArm64, iosSimulatorArm64, linuxArm64, linuxX64, macosArm64, mingwX64, tvosArm64, ...]
Library unique name: <androidx.appstate:appstate>

同时源码路径是:

bash 复制代码
src/commonMain/kotlin/androidx/appstate/AppState.kt
src/commonTest/kotlin/androidx/appstate/AppStateTest.kt

也就是,这个项目不是只给 Android JVM 写的,而是 AndroidX Multiplatform 结构下的 commonMain 库,所以这是一个面向 Kotlin Multiplatform 的项目。

我感觉,它不是传统 SavedStateHandle / ViewModel 的替代品,而更像是 Compose Runtime 层的状态托管基建

对比 ViewModel 大概是:

  • ViewModel 解决的是 Android 架构里的屏幕级状态和业务逻辑访问
  • 而 AppState 更像是,希望某些 MutableState 不被某个 Composable 或 Android component 生命周期限制,那么可以用一个外部 AppState 容器托管

所以 AppState 更像是进一步把 MutableState<T> 本身放进一个统一容器,注释也明确说 beyond individual Android components,这不是"单个 composable 内保存状态",也不是"某个 Activity 内部字段",而是更外层的状态 store。

所以它可能想支持跨组件协作状态?另外 autoClearKey + predicate + listener + LaunchedEffect 这一套设计,看起来更像是当某个关联状态发生变化时,自动清掉另一个状态,感觉可以类似:

ini 复制代码
object CurrentUserKey : AppStateKey<User?>()
​
object DraftMessageKey : AppStateKey<String>(
    autoClearKey = CurrentUserKey,
    predicate = { appState -> true }
)

比如当用户变化时,清理某些跟用户绑定的草稿、缓存、临时 UI 状态 ?当然这只是猜测。

所以,整体看起来,AppState 更像是是 AndroidX 正在引入的一个 Compose Runtime 层状态托管容器

不过项目目前还处于落地阶段,更详细的实现还没有,但是主方向应该差不多,总的来看,核心就是可以把 Compose 状态提升到组件之外,解决多个 Composable / 多个组件之间共享 Compose State 的问题

链接

android-review.googlesource.com/c/platform/...

相关推荐
Zender Han1 小时前
Flutter 轻量存储方案介绍、区别、对比和使用场景
android·flutter·ios
别问,问就是菜鸡1 小时前
阿里云效前端流水线自动化部署
前端·阿里云·自动化·持续部署
燐妤1 小时前
前端HTML编程4:深入学习CSS
前端·学习·html
黄林晴1 小时前
Google Play 强制截止,内购应用必须升级 Billing 8,不改无法更新
android
zhangphil1 小时前
Android RecyclerView+Coil解码Bitmap设置进View,RenderThread上屏显示Graphics
android
2301_816374331 小时前
服务访问的用户认证
前端·网络
XS0301061 小时前
从浏览器到互联网的完整数据流
前端·数据库·servlet·交互
idingzhi1 小时前
A股量化策略日报(2026年05月11日)
android·开发语言·python·kotlin
hhb_6181 小时前
MATLAB数值计算与数据可视化核心技术梳理及实战应用案例解析
前端