【Jetpack Compose基础语法学与练】第8课 rememberSaveable,页面旋转/系统重建保留状态

前言

上一课学习了 if 条件渲染和 LazyColumn 懒加载列表,掌握动态UI与长列表渲染。

我们一直用 remember 保存状态,但它有一个致命缺陷:手机旋转屏幕、系统因内存不足重建Activity时,remember保存的数据会全部丢失,重置为初始值。

本课学习 rememberSaveable ,它能在系统重建(配置变更、进程重启)时自动保存和恢复状态,是真实安卓开发必须掌握的知识点。

前置:完成1~7课,掌握remember、状态、基础布局与列表

一、完整可运行示例源码

kotlin 复制代码
  
package com.example.composefirst

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SaveableDemoPage()
        }
    }
}

@Composable
fun SaveableDemoPage() {
    // rememberSaveable:系统重建时自动保存恢复
    var count by rememberSaveable { mutableIntStateOf(0) }

    Column(modifier = Modifier.padding(20.dp)) {
        Text(text = "当前计数:$count")
        Spacer(modifier = Modifier.height(12.dp))

        Button(onClick = { count++ }) {
            Text("+1")
        }
        Spacer(modifier = Modifier.height(8.dp))

        Button(onClick = { count = 0 }) {
            Text("重置")
        }
    }
}

@Preview
@Composable
fun SaveablePreview() {
    SaveableDemoPage()
}
 

二、逐行代码解读

  1. rememberSaveable { mutableIntStateOf(0) }
    和 remember 用法几乎一模一样,唯一区别:数据会被序列化保存到Bundle中,Activity因配置变更、系统重建的时候,可以自动恢复数据。
    导入路径: androidx.compose.runtime.saveable.rememberSaveable
  2. remember 丢失数据的场景
    旋转屏幕、切换系统深色模式、修改系统字体大小、切换系统语言,这些操作都会触发安卓配置变更,销毁并且重建Activity。
    remember仅仅保存在运行时内存当中,页面重建之后内存清空,状态直接归零。
  3. rememberSaveable 底层原理
    封装安卓原生 onSaveInstanceState 保存机制,把状态序列化放进Bundle,页面重建之后,从Bundle读取数据恢复状态。
    存在功能限制:只能存储可以序列化的数据。整型、字符串、布尔值等基础类型开箱即用;自定义实体类需要实现Parcelable,或者手动提供Saver保存器。
  4. 简单区分 rememberSaveable 和 ViewModel
    rememberSaveable 适合少量UI状态,开箱即用,代码简短。
    ViewModel 适合大批量业务数据、跨页面共享数据,生命周期更长,旋转屏幕不会丢失。ViewModel属于架构进阶内容,后续课程再详细讲解。

三、核心概念文字对比

remember:重组的时候可以保留状态;屏幕旋转、页面重建数据丢失;数据类型没有限制;适合页面临时状态。

rememberSaveable:重组的时候可以保留状态;屏幕旋转、页面重建自动恢复;数据需要支持序列化;适合表单、计数器等需要防丢失的数据。

记忆口诀:临时状态用remember,怕丢数据用rememberSaveable。

四、综合练习题

填空题

  1. 能够在旋转屏幕、系统重建时自动保存恢复状态的函数是________。
  2. rememberSaveable 底层基于安卓传统的________机制,把数据存入Bundle。
  3. rememberSaveable 要求保存的数据类型必须是________的,自定义类需要实现Parcelable。

答案与解析

  1. rememberSaveable ;解析:专门用于跨配置变更、系统重建保存状态。
  2. onSaveInstanceState ;解析:安卓传统保存实例状态机制,Compose封装后自动调用。
  3. 可序列化;解析:Bundle只能存可序列化数据,基础类型默认支持,自定义类需Parcelable。

判断题

  1. remember 和 rememberSaveable 在普通重组时都能保留数据,效果一样。()

答案:正确。理由:两者在Compose重组时都会保存数据,区别只在系统重建场景。

  1. 用remember保存的计数器,旋转屏幕后数值会重置为初始值。()

答案:正确。理由:remember只存在内存中,Activity销毁重建后内存数据清空。

  1. rememberSaveable 可以保存任意类型的数据,包括不可序列化的对象。()

答案:错误。理由:rememberSaveable基于Bundle存储,数据必须可序列化,不可序列化对象会运行时报错。

简答题

  1. 什么场景下应该使用rememberSaveable而不是remember?举两个实际例子。

参考答案:

当状态需要在系统重建(旋转屏幕、语言切换、深色模式切换、内存回收重建)后保留时使用。

例子1:用户在表单页输入了一半内容,旋转屏幕后不能清空;

例子2:计数器页面,用户点了很多次,旋转屏幕后数值要保留。

代码实操题

把第7课的待办列表示例改造:输入文本和待办列表都使用rememberSaveable保存,确保旋转屏幕后数据不丢失。写出关键状态定义代码。参考答案

kotlin 复制代码
  
@Composable
fun TodoListPage() {
    var inputText by rememberSaveable { mutableStateOf("") }
    var todoList by rememberSaveable { mutableStateOf(listOf<String>()) }

    fun addTodo(item: String) {
        todoList = todoList + item
    }

    fun removeTodo(item: String) {
        todoList = todoList - item
    }
    // ... 其余UI代码和第7课一致
}
 

解析:

inputText是字符串,默认可序列化,直接使用rememberSaveable。

todoList采用不可变List,增删时生成全新集合进行赋值,正常触发重组。

注意:mutableStateListOf直接套rememberSaveable存在兼容隐患,练习场景优先选用不可变列表。

五、本课小结

  1. remember 仅重组保数据,屏幕旋转、页面重建数据丢失。
  2. rememberSaveable 依托安卓实例保存机制,系统重建自动恢复状态。
  3. 存入的数据需要支持序列化,自定义对象需要额外实现Parcelable。
  4. 选型参考:临时界面状态用remember,需要防丢失的数据选用rememberSaveable。

下一课:SideEffect副作用 + LaunchedEffect,处理异步任务和生命周期。

相关推荐
代码山河5 小时前
Python就业方向全解析:后端、爬虫、数据分析、AI你选哪个?
python·学习·架构·教程·面向对象·项目
释厄6235 小时前
AI学习层更新与跨体转移律——人类社会同构·不缺理解缺 U
人工智能·学习
驰骋工作流5 小时前
流程时效考核的表结构:从待办时限到 WF_CH 考核结果驰骋BPM驰骋低代码低代码工作流引擎
android·低代码·rxjava
oicola6 小时前
【UI动效】科幻风长任务进度动效设计方案
ui
传奇开心果编程7 小时前
【Flutter踩坑排雷】第7课:巨型 build 函数坑|全部 UI 写在同一个 build,维护难、隐性异常
android·flutter·ios·移动开发·跨平台·dart·声明式ui
我是唐青枫8 小时前
Kotlin Delegation 委托详解
开发语言·kotlin
小嘉丶学长9 小时前
Day14 · 字典与集合
java·开发语言·网络·python·学习·1024程序员节
小李不想当小白10 小时前
SPI通信外设与W25Q64 (硬件SPI)(STM32标准库学习笔记)
笔记·stm32·单片机·嵌入式硬件·学习·嵌入式
方白羽11 小时前
Android 双开环境底层剖析与风控检测落地
android·安全·app
weixin_5633714711 小时前
Android Studio 2024 版 Device Explorer 打开方法
android·ide·android studio