Android Compose 《编程思想》解读

文章目录

官方文档

Compose 编程思想

声明性编程范式

  • widget的实现是,修改view的属性,继而影响 UI,刷新/重绘界面

在传统的 Android UI 开发中,界面和数据是分离的,你需要手动去"命令" UI 进行修改。这很容易导致状态不同步的 Bug。

痛点:随着界面越来越复杂,你要记住 "这个数据的变化,引起的每一处需要更新的 View,一旦漏写了一句,界面就会显示错误"

  • 声明性界面模型中,不能直接获取到某个ui组件,再修改它的属性。而是通过声明 不同 State (状态) 的 UI,在 修改 State 后,发生 可组合项的重组,并刷新界面。会智能重组,某些可组合项会跳过重组。原文:Compose 会智能地选择在任何给定时间需要重新绘制界面的哪些部分

核心公式:UI = f(State)

声明性 UI 的核心可以用一个数学公式表示:UI = f(State)

State (状态):应用的数据。

f (函数):你的 Compose UI 代码。

UI (界面):最终屏幕上显示的内容。

这意味着:

界面只是当前状态在某一时刻的视觉快照。

你不能直接去修改 UI(比如 tv.text = "新文字" 这种做法在 Compose 里是不存在的)。

你要做的仅仅是修改状态(State)。一旦状态改变,Compose 就会带着新的状态重新运行那个函数 f(即重组 Recomposition),从而画出新的 UI。


可组合项,重组是智能的

可能会频繁、并行、无序地 进行重组,也可能会智能跳过某些可组合项的重组。

不应在 可组合函数 展示 UI 元素的地方,利用重组的附带效应(Side Effect),执行文件读写、网络访问等操作。

附带效应:可组合项被框架,智能重组调用的时机、次数 及是否会调用都是不受人为控制的,那在重组过程中 频繁执行 io密集/cpu密集操作 都是不可取的

若一定要执行 这些耗时操作,也行的。可以在 LaunchedEffect(key) { } 这个协程作用域中执行。它会执行多少次呢?

LaunchedEffect 的执行次数完全取决于你传给它的 key(键值)。

它的核心运行规则是:

  • 第一次进入界面时(进入组合区),必定执行 1 次。
  • 在随后的 UI 重组中,只有当 key 发生变化时,才会先取消上一次正在执行的任务,然后重新执行 1 次。
  • 当它所在的 UI 节点从屏幕上消失时(离开组合区),它内部的协程会被自动取消。

根据你传入的 key 的不同,通常有以下两种典型场景:
场景 1 :只执行 1 次(常用于初始化)

如果你希望某个操作在整个 UI 生命周期内只执行一次,无论界面重组多少次都不再执行,你可以传入一个常量(通常是 Unit 或 true)。

kotlin 复制代码
@Composable
fun MyScreen() {
    // 传入 Unit 作为 key
    LaunchedEffect(Unit) {
        // 这里的代码只会在 MyScreen 第一次显示时执行 1 次
        // 即使 MyScreen 因为其他状态变化重组了 100 次,这里也不会再执行
        fetchDataFromNetwork() 
    }
    // UI 代码...
}

场景 2 :根据变量变化执行 N 次(常用于参数变化时的重新加载)

如果你希望当某个特定的状态或参数改变时,重新触发操作,你就把那个变量作为 key 传进去。

kotlin 复制代码
@Composable
fun UserProfile(userId: String) {
    // 将 userId 作为 key
    LaunchedEffect(userId) {
        // 1. 第一次进入界面时,执行 1 次获取用户信息
        // 2. 如果重组时,userId 的值变了(比如从 "001" 变成了 "002"),
        //    Compose 会自动取消之前未完成的 "001" 请求,并重新执行 1 次获取 "002" 的请求。
        // 3. 如果重组时,userId 没变,这里绝不会执行。
        val user = api.getUser(userId) 
    }
}
相关推荐
HLC++10 小时前
Linux的进程间通信
android·linux·服务器
爱笑鱼14 小时前
Binder(二):AIDL 生成的 Proxy、Stub 和 Parcel 到底在做什么?
android
爱笑鱼14 小时前
Binder(一):一次方法调用,究竟怎样跨进程执行?
android
壮哥_icon15 小时前
【Android 系统开发】使用 BAT 脚本高效自动化管理 /system/priv-app/ 系统应用(安装与卸载)
android·运维·自动化
用户693717500138416 小时前
Claude Code终端日志Token占用实测:一个过滤器砍掉60%-90%
android·前端·后端
蝉蜕日记17 小时前
AccumuPDF高级版 v2.57 | 视图文转换PDF,合并分割压缩
android·智能手机·pdf·生活·软件需求
吐了啊取名字太难17 小时前
美颜系统AI修图本地跑并支持Mac、win、安卓、iOS不卡顿
android·人工智能·windows·数码相机·mac·ai编程
阿pin18 小时前
Android随笔-Retrofit
android·retrofit
想取一个与众不同的名字好难18 小时前
安卓自定义颜色选择器
android
我命由我1234519 小时前
Android 开发问题:java.lang.NoSuchMethodError:No virtual method readAllBytes()
android·java·java-ee·kotlin·android studio·android-studio·android runtime