1、Compose编程思想

30 阅读4分钟

1. 声明性编程范式

传统视图层次结构的挑战

  • Android传统视图层次结构以界面widget树的形式表示。
  • 应用状态变化时,需手动更新视图层次结构以显示最新数据。
  • 常见更新方式包括使用findViewById()等函数遍历树,并通过调用button.setText()container.addChild()等方法更改节点状态。
  • 手动操纵视图易出错,尤其是数据在多个位置呈现时,可能忘记更新某个视图,或导致非法状态。

声明性界面模型的兴起

  • 近年来,行业转向声明性界面模型,简化了构建和更新界面的工程任务。
  • 声明性模型概念上从头开始重新生成整个屏幕,但仅执行必要的更改,避免了手动更新有状态视图层次结构的复杂性。

Jetpack Compose的声明性特性

  • Jetpack Compose是一个声明性界面框架,简化了应用界面的编写和维护。
  • 通过定义接受数据并发出界面元素的可组合函数来构建界面。

2. 可组合函数的核心概念

可组合函数定义

  • 使用@Composable注解标记,告知Compose编译器该函数用于将数据转换为界面。
  • 接受参数以描述界面,不返回任何内容,因为它们描述目标屏幕状态。

可组合函数的属性

  • 快速:执行效率高,避免在界面更新时造成卡顿。
  • 幂等:使用相同参数多次调用时,行为一致。
  • 无附带效应:不修改全局变量或产生对其他部分可见的更改。

示例:Greeting Widget

@Composable
fun Greeting(name: String) {
    Text("Hello $name")
}
  • 接受一个String参数,用于在界面上显示问候消息。

3. 声明性范式转变

命令式与声明式的对比

  • 命令式:通过实例化widget树初始化界面,通常通过膨胀XML布局文件实现。每个widget维护自己的内部状态,提供getter和setter方法与应用逻辑交互。
  • 声明式:widget相对无状态,不提供setter或getter函数。通过调用带有不同实参的同一可组合函数来更新界面,简化了向架构模式(如ViewModel)提供状态的过程。

界面更新流程

  • 应用逻辑为顶级可组合函数提供数据。
  • 可组合函数通过调用其他可组合函数描述界面,并传递数据。
  • 用户与界面交互时,触发事件通知应用逻辑,应用逻辑改变状态后,系统使用新数据再次调用可组合函数,导致界面元素重新绘制(重组)。

4. 动态内容与灵活性

动态界面构建

  • 可组合函数用Kotlin编写,可像其他Kotlin代码一样动态。
  • 示例:构建一个问候多个用户的界面。
@Composable
fun Greeting(names: List<String>) {
    for (name in names) {
        Text("Hello $name")
    }
}
  • 接受名称列表,为每个用户生成问候语。

条件与循环

  • 可组合函数内可使用if语句、循环等,拥有底层语言的全部灵活性。

5. 重组机制

重组定义

  • 输入更改时,再次调用可组合函数的过程。
  • Compose根据新输入智能重组,仅调用可能已更改的函数或lambda,跳过其余部分。

重组优化

  • 避免重组整个界面树,减少计算量和电池消耗。
  • 重组是乐观的操作,可能会被取消。如果参数在重组完成前更改,Compose会取消当前重组,使用新参数重新开始。

可组合函数编写建议

  • 保持快速:避免在可组合函数中执行成本高昂的操作。
  • 幂等且无附带效应:确保函数行为一致,不产生对其他部分可见的更改。
  • 使用参数传递数据:避免从共享偏好设置等源头直接读取数据,应在后台协程中读取,并将结果作为参数传递。

6. 可组合函数的执行特性

执行频率

  • 可组合函数可能非常频繁地运行,如界面动画的每一帧。

并行执行

  • Compose可能并行运行可组合函数,利用多个核心优化重组。
  • 可组合函数可能在后台线程池中执行,调用可能发生在不同线程上。

执行顺序

  • 可组合函数可以按任何顺序执行,不保证按代码出现顺序运行。
  • 每个可组合函数应保持独立,不依赖其他函数的执行顺序或附带效应。

7. 最佳实践与注意事项

避免附带效应

  • 切勿在可组合函数中产生附带效应,如写入共享对象属性、更新ViewModel中的可观察项等。
  • 应通过回调触发附带效应,确保在界面线程上执行。

线程安全

  • 编写可组合函数时考虑多线程环境,避免使用非线程安全的代码。
  • 不应在可组合lambda中修改变量,因为这可能导致不可预测的行为。

资源利用

  • 合理利用资源,避免在可组合函数中执行阻塞操作,以免影响界面性能。

通过遵循这些编程思想和最佳实践,可以更有效地使用Jetpack Compose构建高效、灵活且易于维护的Android应用界面。