State and Jetpack Compose,状态值

149 阅读3分钟

概论

Compose的UI更新,依赖,状态驱动UI更新的思想。 Compose 的状态驱动 UI 思想:

UI = f(state)

state 发生变化时,Compose 会自动重新调用相关的 @Composable 函数,只更新有变化的部分。这就是为什么 mutableStateOf(...) 是 Compose 中管理 UI 状态的关键。

Compose 状态的原理简图:

remember {
    mutableStateOf("Hello")
}
↓
→ 构建时保存状态
→ 当状态 .value 改变
→ Compose 标记该 UI 为 “脏”
→ 在下一个帧(frame)中进行 Recomposition(重新组合)
→ 只重组使用该状态的 Composable

使用方式

val mutableState = remember { mutableStateOf(default) }

🔍 说明:
  • mutableState 是一个 MutableState<T> 对象,它有 .value 属性。
  • 状态改变需要手动 .value = ...
  • 使用方式:
val nameState = remember { mutableStateOf("John") }

TextField(
    value = nameState.value,
    onValueChange = { nameState.value = it }
)

var value by remember { mutableStateOf(default) }

🔍 说明:
  • 使用 Kotlin 的 属性委托(by)语法糖
  • 编译器会自动导入 .value 的 getter 和 setter
  • 使用方式:
var name by remember { mutableStateOf("John") }

TextField(
    value = name,
    onValueChange = { name = it }
)


✅ 优点:
  • 简洁、易读,是 Compose 中最常用的方式
  • 推荐用于局部状态(如按钮状态、输入框值等)

⚠️ 关键导入(别忘记):

import androidx.compose.runtime.getValue
import androidx.compose.runtime.setValue


val (value, setValue) = remember { mutableStateOf(default) }

🔍 说明:
  • Kotlin 的解构写法(适用于 MutableStatecomponent1() / component2() 支持的)
  • value 是状态值,setValue() 是设置方法
val (name, setName) = remember { mutableStateOf("John") }

TextField(
    value = name,
    onValueChange = { setName(it) }
)

✅ 优点:
  • 语义清晰,适合函数式风格(像 React 的 useState
  • 可作为参数传递给组件(回调函数)
⚠️ 注意:
  • 虽然解构写法是有效的,但在 Compose 中用得相对较少,除非你习惯这种写法。

配置变更后的状态保存

rememberSaveable 是 Jetpack Compose 提供的一个用于自动保存和恢复状态的 API,特别适合在 屏幕旋转进程重建 后保留用户界面状态。

✅ 简洁定义

rememberSaveable = remember + 自动保存/恢复状态
底层是通过 SavedStateHandleBundle 实现的。

🧪 使用方式

✅ 基本用法:

var name by rememberSaveable { mutableStateOf("") }

  • 当用户输入内容后,即使旋转屏幕,输入值也不会丢失;配置变更后,经历了保存,恢复的过程

  • 相比之下,remember 就会失效。

✅ 使用列表或复杂结构

对于 List<String>Map 等结构也可以用:

var items by rememberSaveable { mutableStateOf(listOf("A", "B")) }

但注意:数据类型必须是可序列化的(如 String, Int, List)

❌ 不支持的类型(默认情况下)

rememberSaveable 默认使用 Bundle 存储状态,因此不支持保存如下类型:

  • 自定义类(除非实现了 Parcelable / Serializable
  • 高阶函数(Lambda)
  • 非可序列化对象(如某些 ViewModel 状态)

✅ 支持自定义类型保存(高级用法)

可以通过 Saver 来让 rememberSaveable 保存自定义对象:

    data class User(val name: String, val age: Int)

val UserSaver = Saver<User, List<Any>>(
    save = { listOf(it.name, it.age) },
    restore = { User(it[0] as String, it[1] as Int) }
)

var user by rememberSaveable(saver = UserSaver) {
    mutableStateOf(User("Tom", 20))
}

代码含义解释:状态变量是user,类型为User;该状态变量的保存和恢复的定义,由UserSaver来定义。具体的说,每个状态变量,保存到list表中,由save方法实现;每个状态变量的恢复,值从list中获取,由restore方法实现。

📌 remember vs rememberSaveable 对比

特性rememberrememberSaveable
作用周期仅当前组合过程配置变更中保持(如旋转)
可恢复能力❌ 不可恢复✅ 自动保存和恢复
可保存类型任意类型只能保存基本类型、可序列化对象
原理存在于内存中存入 Bundle/ViewModelState
## 📍适用场景
适用场景是否使用 rememberSaveable
表单输入(用户名、搜索框)✅ 是,避免旋转丢失输入
Tab切换状态✅ 保存当前Tab索引
页面滚动位置✅ 保存列表偏移量
一次性 UI 逻辑(临时变量)❌ 用 remember 即可
大对象/复杂业务状态❌ 推荐使用 ViewModel

✅ 示例对比:旋转屏幕是否保留状态

    // 旋转后丢失
var count by remember { mutableStateOf(0) }

// 旋转后保留
var count by rememberSaveable { mutableStateOf(0) }