remember 原理与使用指南

568 阅读2分钟

remember 原理与使用指南

remember 是 ​Jetpack Compose​ 中的核心函数,用于在组件的重组(Recomposition)过程中保持状态或缓存计算结果。以下是它的实现原理、核心特性和用法:


一、实现原理

1. ​编译期处理

  • Compose 编译器会为 @Composable 函数生成特殊代码,在编译时记录 remember 的调用位置和依赖关系。
  • 每个 remember 调用会被分配一个唯一的 ​记忆槽(Memory Slot)​,存储在 Composition 的插槽表中。

2. ​运行时机制

  • 首次组合(Initial Composition)​​:执行 remember 的 lambda 并存储结果到插槽表。
  • 重组期间​:直接读取插槽表中存储的值,除非依赖项变化。
  • 插槽表结构​:Compose 通过树形结构的插槽表跟踪所有 remember 的状态,重组时根据位置信息找回对应值。

3. ​位置记忆(Positional Memoization)​

  • Compose 通过调用位置(代码中的物理位置)区分不同的 remember 实例。
  • 这也是为什么 remember 必须稳定地出现在相同调用位置(不能放在条件分支中动态切换)。

二、基本作用

  • 状态持久化​:在重组时保留存储的值,避免重新初始化。
  • 性能优化​:缓存计算结果,避免重复执行耗时操作。

三、基本语法

val value = remember { 
    // 初始值或计算逻辑(仅在首次组合时执行)
    expensiveCalculation() 
}
  • 当 Composable 重组时,value 会保持上一次的结果,除非依赖项变化。

四、与 mutableStateOf 结合

var count by remember { mutableStateOf(0) } // 委托语法
  • 当 count 变化时,依赖它的 Composable 会自动重组。

五、依赖项控制(key)

val result = remember(key1 = dep1) {
    computeValue(dep1) // dep1变化时重新计算
}

六、常见使用场景

  1. 状态保持​:表单输入、开关状态

    var text by remember { mutableStateOf("") }
    
  2. 缓存计算​:排序/过滤等耗时操作

    val sortedList = remember(list) { list.sorted() }
    

七、与 rememberSaveable 的区别

特性rememberrememberSaveable
重组保持
配置变更保持✅(通过 Bundle)
适用场景临时状态需要持久化的状态

八、注意事项

  1. 位置稳定性​:避免将 remember 放在条件分支中。

    // 错误用法!可能导致状态丢失
    if (condition) {
        val x = remember { ... }
    }
    
  2. 内存管理​:未使用的 remember 值会在离开 Composition 时自动清除。


完整示例

@Composable 
fun Counter() {
    // 原理:值存储在插槽表第0位置
    var count by remember { 
        mutableStateOf(0) // 首次组合初始化
    }
    
    // 原理:值存储在插槽表第1位置
    val square = remember(count) { 
        count * count // count变化时重新计算
    }

    Button(onClick = { count++ }) {
        Text("$count² = $square")
    }
}

通过理解 remember 的插槽表机制和位置记忆原理,可以更精准地控制 Composable 的状态生命周期。