001 Compose 入门与从 XML 迁移的心智模型
大家好,今天我想和大家聊聊我学习 Jetpack Compose 的入门心得,特别是从传统 XML 布局迁移过来的思维转变。这不仅仅是学习一个新框架,更是一次编程范式的转换,理解了这一点,后面的路会好走很多。
1. 为什么要有 Compose?
在传统的 Android 开发里,我们是怎么做的呢?我们先用 XML 描述一个静态的界面结构,然后在运行时,用 Kotlin 或 Java 代码去找到那些 View 节点,再修改它们的属性。整个过程就像是,你先画好一棵树(XML),然后拿着地图(findViewById 或 ViewBinding)去找到特定的树枝,再手动给它挂上叶子或改变颜色。
而 Compose 带来了一种全新的思路:我们直接用 Kotlin 函数来描述「在当前状态下,界面应该长什么样」。我们不再关心如何找到并修改某个具体的 TextView,我们只关心数据(状态)。当数据变化时,框架会根据状态的变化,智能地决定屏幕的哪些部分需要更新,并自动完成渲染。这感觉就像是,你只需要告诉系统“现在要显示这些内容”,系统就会帮你把一切都安排好,省去了大量手动操作的繁琐。
2. 核心概念对照
为了帮助大家更快地建立映射关系,我整理了一个从 View 体系到 Compose 的核心概念对照表,这在我初期学习时非常有用:
| XML / View 体系 | Compose |
|---|---|
Activity + setContentView(R.layout.xxx) |
Activity + setContent { ... } |
LayoutInflater 膨胀布局 |
Composable 函数直接「调用即生成」描述 |
TextView |
Text |
Button |
Button / TextButton |
EditText |
TextField / OutlinedTextField |
onClick 在 XML 或 setOnClickListener |
onClick = { } 参数 |
数据变 → 手动 textView.text = ... |
数据变 → 状态驱动重组,自动反映到 UI |
看到最后一行了吗?这就是思维转变的关键:从“命令式”的修改,变成了“声明式”的响应。
3. 最小可运行结构
光说不练假把式,我们来看看如何搭建一个最简单的 Compose 项目。首先,你得在模块的 build.gradle.kts 里做好配置。
Gradle(模块 build.gradle.kts 片段)
android {
buildFeatures {
compose = true
}
composeOptions {
kotlinCompilerExtensionVersion = "1.5.14" // 与 Kotlin 版本按官方表对齐
}
}
dependencies {
val composeBom = platform("androidx.compose:compose-bom:2024.10.01")
implementation(composeBom)
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.compose.ui:ui-tooling-preview")
debugImplementation("androidx.compose.ui:ui-tooling")
implementation("androidx.activity:activity-compose:1.9.3")
}
这里我强烈推荐使用 BOM(Bill of Materials)来统一管理 Compose 相关库的版本,它能帮你避免版本冲突的噩梦。具体的版本号需要根据你项目的 Kotlin 和 AGP 版本,去查阅官方的 Compose 与 Kotlin 兼容表。
Activity
配置好了,我们来写一个最简单的 Activity。你会发现,它和以前的结构很像,但 setContent 里面的世界完全不同了。
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MaterialTheme {
Surface {
Text("Hello Compose")
}
}
}
}
}
这段代码的功能,就等价于以前我们写一个只包含 TextView 的 activity_main.xml 文件,然后在 onCreate 里调用 setContentView(R.layout.activity_main)。是不是感觉更简洁、更“代码即UI”?
4. Composable 函数
Compose 的 UI 都是由一个个 Composable 函数 构建的。这是你未来最常打交道的伙伴。
- 用
@Composable注解来标记它。 - 命名上有个习惯,采用 PascalCase,比如
GreetingScreen、UserProfile。 - 这里有一个非常重要的原则(初期容易踩坑):不要在 Composable 函数里做繁重的计算、生成随机数或者读取非 Compose 管理的状态而不做声明,否则重组(Recomposition)的行为会难以预测。关于副作用管理和
remember,我们后续会详细讲。
来看一个简单的例子:
@Composable
fun Greeting(name: String) {
Text(text = "Hello, $name")
}
当你调用 Greeting("Compose") 时,你并不是在创建一个 View 对象并把它挂到视图树上。你只是在向框架描述:“这里应该有一段显示 ‘Hello, Compose’ 的文字”。至于如何创建和更新这个 UI 元素,是框架运行时的工作。这种“描述而非构建”的感觉,需要慢慢体会。
5. 重组(Recomposition)——和 XML 最大的思维差别
重组 是 Compose 的核心机制,也是和 XML/View 体系思维差异最大的地方。
- 当 Compose 检测到某个 Composable 函数的输入参数发生了变化,或者它内部读取的状态发生了变化,它就会再次执行这个函数(以及它内部需要更新的子组件)。
- 这个过程是细粒度的,并不是整个屏幕刷新。框架非常智能,它会跳过那些输入没有变化的组件,只重组需要更新的部分。
迁移思维提示: 以前我们数据变了,可能要到处调用 notifyDataSetChanged(),或者手动去设置 view.visibility = GONE。在 Compose 的世界里,更常见的模式是:你只需要改变某个状态(State)的值,UI 就会自动地、正确地随之更新。你从“指挥官”变成了“规则制定者”。
6. 预览(可选但强烈建议)
Compose 提供了强大的预览功能,能极大提升开发效率。它类似于以前 XML 的 Layout Preview,但更灵活,因为你的 UI 就是代码。
import androidx.compose.ui.tooling.preview.Preview
@Preview(showBackground = true)
@Composable
private fun GreetingPreview() {
MaterialTheme {
Greeting("Preview")
}
}
在 Android Studio 中,你可以打开分屏预览,一边写代码,一边实时看到 UI 效果,这种所见即所得的体验非常棒。
7. 本篇小结与练习
好了,我们来总结一下今天的核心:请记住,Compose 是关于声明“状态如何映射到 UI”,而不是去找到某个 View 然后设置它的属性。
为了巩固这个思维,我建议大家做一个小练习:
尝试用 Compose 写一个简单的页面,只包含一个标题 Text 和一个副标题 Text。然后,回想或者实际用 ConstraintLayout 写一个 XML 来实现同样的界面。对比一下两者所需的文件数量和代码量,你会直观地感受到 Compose 在简洁性和表达力上的优势。
理解了这些基础心智模型,我们就可以继续探索更具体的布局和组件了。下一篇,我们会详细聊聊:002-布局Modifier与常用组件对照.md,我们下次见!
当前文章价值5.08元,扫一扫支付后添加微信提供帮助!(如不能解决您的问题,可以申请退款)

评论已关闭!