【Android】【Compose】Compose知识点复习(二)

可观察状态
状态类型与核心特点对照表
状态类型 核心特点 典型场景
mutableStateOf 基础单值可观察状态,修改 value 触发重组 计数器、开关、输入框文本、按钮状态
mutableStateListOf 列表元素变化触发重组 购物车、待办清单、动态列表
mutableStateMapOf Map 键值对变化触发重组 用户配置、筛选条件、键值对数据
StateFlow + collectAsState 跨组件共享状态,支持异步 页面级共享状态、异步数据更新
derivedStateOf 派生计算,仅结果变化触发重组(性能优化) 滚动阈值、多状态组合计算
Flow + collectAsState 普通 Flow 转可观察状态 单次异步请求(网络/数据库)
remember ()

remember() 是 Compose 的 "状态存储器",作用是在组件重组时保留状态值,避免每次重组都重新创建状态(比如mutableStateOf)。

通俗理解

把 Compose 重组比作 "教室换座位":

没有remember():每次换座位,你都把笔记本扔了,重新拿个新本(mutableStateOf(0)重新创建,值重置为 0);

有remember():换座位时把笔记本装在书包里带走(状态被保留,值不会重置);

注意:remember() 只在 "同一重组作用域" 内有效 ------ 如果组件被销毁重建(比如页面跳转后返回),状态还是会丢失(此时需要用rememberSaveable,但核心是remember的 "记忆" 特性)。

踩坑提醒:一定要加 remember!

如果忘记加remember(),会出现 "点击加 1 后,一重组就变回 0" 的诡异问题:

java 复制代码
@Composable
fun RememberPitfallDemo() {
    // 错误:无remember,每次重组都重置为0
    val noRememberState = mutableStateOf(0)
    // 正确:有remember,重组时保留值
    val rememberState = remember { mutableStateOf(0) }

    Column {
        Text("无remember:${noRememberState.value}") // 永远是0(重组就重置)
        Text("有remember:${rememberState.value}") // 保留当前值
        Button(onClick = { 
            noRememberState.value++ 
            rememberState.value++ 
        }) { Text("点击加1") }
    }
}

日常开发中,remember和mutableStateOf几乎是 "绑定使用" 的:

java 复制代码
// 标准写法:创建可观察状态并保留
var count by remember { mutableStateOf(0) }
= vs by
写法 变量类型 读取方式 修改方式 本质 适用场景
val state = remember { mutableStateOf(0) } MutableState<Int>(容器) state.value state.value++ 直接持有状态容器本身 需要操作容器(传递/比较)
var count by remember { mutableStateOf(0) } Int(容器内的值) count count++ 通过委托访问容器内的值 简化语法,直接操作值
通俗理解

把MutableState比作 "带盖子的盒子":

= 写法:你直接拿到了 "整个盒子",要拿 / 放里面的东西,必须先打开盖子(.value);

by 写法:你委托别人帮你管盒子,不用碰盒子本身,直接拿 / 放里面的东西(编译器自动开盖子)。

by 是 Kotlin 的委托语法糖,Compose 给MutableState实现了ReadWriteProperty接口,编译器会自动帮你补全.value:

java 复制代码
// by 写法的等价代码(编译器自动生成)
val countDelegate = remember { mutableStateOf(0) }
var count: Int
    get() = countDelegate.value // 读取时自动加.value
    set(value) { countDelegate.value = value } // 修改时自动加.value
注意点

by 写法必须用var(因为要修改值),用val会编译报错;

= 写法建议用val(容器本身不用重新赋值,只改内部.value);

两种写法的重组效果完全一致,没有性能差异,仅语法不同。

无状态 + 状态提升 + 单向数据流
概念 核心定义
无状态组件 组件内部不持有状态,所有状态由外部传入,仅负责"展示 UI"和"转发事件"
状态提升 将组件的内部状态"提到"父组件管理,子组件通过参数接收状态和回调函数
单向数据流 状态只能"从父到子"传递(读),修改需通过子组件调用父组件回调(写),形成闭环
通俗理解:用 "餐厅点餐" 类比

无状态组件 = 服务员:不记顾客点了什么(不持有状态),只负责把点餐需求传给前台(父组件),把菜品端给顾客(展示 UI);

状态提升 = 点餐状态交给前台:服务员(子组件)不存菜单,所有点餐信息集中在前台(父组件),避免多个服务员记的菜单不一致;

单向数据流 = 点餐流程:顾客→服务员→前台→后厨(状态传递:父→子),后厨做好菜→前台→服务员→顾客(事件回调:子→父),全程单向,不混乱。

反例 vs 正确示例
反例(有状态组件,不推荐)

子组件自己持有状态,父组件无法控制,复用性差:

java 复制代码
// 有状态子组件:内部持有count,父组件无法获取/修改
@Composable
fun BadCounter() {
    var count by remember { mutableStateOf(0) }
    Button(onClick = { count++ }) { Text("计数:$count") }
}
正确示例(无状态 + 状态提升 + 单向数据流)
java 复制代码
// 1. 无状态子组件:只接收状态和回调,不持有状态
@Composable
fun GoodCounter(
    count: Int, // 从父组件接收状态(读)
    onCountAdd: () -> Unit // 从父组件接收回调(写)
) {
    Button(onClick = onCountAdd) { Text("计数:$count") }
}

// 2. 父组件:管理状态,实现单向数据流
@Composable
fun CounterParent() {
    var count by remember { mutableStateOf(0) } // 父组件持有状态
    Column {
        // 状态从父到子(读),修改通过回调(写)→ 单向数据流
        GoodCounter(count = count, onCountAdd = { count++ })
        Text("父组件同步显示:$count") // 父组件可复用状态,灵活扩展
    }
}
核心优势

无状态组件:可复用性强(同一个组件传入不同状态就能展示不同内容)、易测试(传固定状态即可验证 UI);

状态提升:状态集中管理,避免多个组件持有同一份状态导致数据不一致;

单向数据流:状态变化可追踪,所有修改都通过回调函数,调试时能快速找到 "谁改了状态"。

相关推荐
千里马学框架1 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台1 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone1 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc1 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo1 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077001 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼1 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone1 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen1 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone1 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui