compose编码09-状态管理mutableStateOf 和 remember、rememberSaveable、viewModel

Jetpack Compose 的状态管理是其响应式 UI 的核心。简单来说,状态就是任何可以随时间变化的值,而 Compose 的核心任务就是当状态变化时,自动更新界面(这个过程称为“重组”)。

核心概念:状态与重组

在 Compose 中,UI 是状态的函数:UI = f(state)。你不再需要像在传统 View 系统中那样手动调用 setText() 来更新界面,而是改变状态,Compose 会自动完成更新。

  • 状态(State):应用的任何可变数据,比如一个数字、一个类实例、或一个列表的滚动位置。
  • 重组(Recomposition):当状态发生变化时,Compose 会重新执行读取了该状态的 @Composable 函数,以反映出最新状态。这个过程是智能且高效的,只会更新需要变化的部分。

如何在可组合项中创建和管理状态

@Composable 函数中,我们使用 mutableStateOfremember 来创建可被 Compose 追踪的状态。

  • mutableStateOf:这个函数会创建一个可观察的 MutableState 对象。当它的 value 发生变化时,所有读取这个值的可组合函数都会被自动调度进行重组。
  • remember:由于重组时会重新执行函数,如果没有 remember,状态值会被重置。remember 可以将值存储在内存中,确保在重组后值仍然保留。

三种等价的声明方式

// 方式一:直接操作 .value
val name = remember { mutableStateOf("") }
TextField(value = name.value, onValueChange = { name.value = it })

// 方式二:使用 by 委托(最常用,代码简洁)
var name by remember { mutableStateOf("") }
TextField(value = name, onValueChange = { name = it })

// 方式三:解构声明
val (name, setName) = remember { mutableStateOf("") }

使用 by 委托需要导入 import androidx.compose.runtime.getValuesetValue

配置更改后的状态保留:rememberSaveable

remember 无法在屏幕旋转等配置更改后保留状态。这时应使用 rememberSaveable,它能利用 Android 的 Bundle 机制自动保存和恢复状态。

// 屏幕旋转后,name 的值依然保留
var name by rememberSaveable { mutableStateOf("") }

对于非基础类型的数据,可以使用 @Parcelize 注解,或通过自定义 Saver(如 mapSaverlistSaver)来保存。

架构模式:状态提升与单向数据流

为了实现可复用、可测试的组件,Compose 推荐使用状态提升模式,将状态移到调用方,使组件变为无状态

  • 有状态 (Stateful):组件自己管理状态,对于简单的、自包含的逻辑很方便,但复用和测试较困难。
  • 无状态 (Stateless):组件不持有任何状态,所有数据通过参数传入,事件通过回调(如 onClick)传出。这是更推荐的模式,因为它职责清晰、可复用性高。

状态提升示例

// 无状态组件:只负责显示和发送事件
@Composable
fun HelloContent(name: String, onNameChange: (String) -> Unit) {
    TextField(value = name, onValueChange = onNameChange)
}

// 有状态容器:管理状态并传递给无状态组件
@Composable
fun HelloScreen() {
    var name by rememberSaveable { mutableStateOf("") }
    HelloContent(name = name, onNameChange = { name = it })
}

这个模式被称为单向数据流:状态(数据)从上(HelloScreen)向下(HelloContent)传递,事件(行为)从下向上传递。

与其他数据流的集成

Compose 可以轻松与 FlowLiveDataRxJava 等常见的响应式数据源集成,只需将它们转换为 State 即可。

  • collectAsStateWithLifecycle():在 Android 中,推荐使用此 API 以生命周期感知的方式从 Flow 收集数据,更加节省资源。
  • collectAsState():用于跨平台通用代码,从 Flow 收集数据。
  • observeAsState():用于将 LiveData 转换为 State

性能优化:在正确的阶段读取状态

Compose 渲染一帧分为组合 (Composition)布局 (Layout)绘制 (Drawing) 三个阶段。为了优化性能,我们应该尽可能在布局或绘制阶段读取状态,避免不必要的重组。

例如,对于滚动偏移,在 Modifier.offset { } 的 lambda 中读取状态,Compose 就能跳过组合阶段,直接进入布局阶段,性能更好。

总结

  • 核心公式UI = f(state)
  • 基础工具:在可组合项中用 remember { mutableStateOf(initialValue) } 创建状态。
  • 数据持久化:用 rememberSaveable 应对配置更改。
  • 架构设计:优先采用状态提升单向数据流模式。
  • 数据源集成:使用 collectAsStateWithLifecycle() 等 API 连接 Flow/LiveData
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容