一、一个让无数Android开发者头疼的老问题
先看一段你可能非常熟悉的代码。假设我们要实现一个最简单的功能:点击按钮,让一段文字显示或隐藏。
用传统XML + View的方式,你需要这样做:
在 activity_main.xml 里定义布局:
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/messageText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="你好,世界"
android:visibility="visible" />
<Button
android:id="@+id/toggleButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="隐藏" />
</LinearLayout>
然后在 MainActivity.kt 里写逻辑:
class MainActivity : AppCompatActivity() {
private var isVisible = true
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val messageText = findViewById<TextView>(R.id.messageText)
val toggleButton = findViewById<Button>(R.id.toggleButton)
toggleButton.setOnClickListener {
isVisible = !isVisible
if (isVisible) {
messageText.visibility = View.VISIBLE
toggleButton.text = "隐藏"
} else {
messageText.visibility = View.GONE
toggleButton.text = "显示"
}
}
}
}
这段代码能跑,效果也没问题。但你有没有觉得哪里“别扭”?
你需要做三件事:在XML里定义界面长什么样、在Kotlin里找到这些界面元素、手动告诉它们该怎么变。界面和数据是分开的两套东西,你必须时刻确保它们保持一致。一旦界面变复杂——比如加载状态、错误提示、空数据页面都要处理——手动同步的工作量就会急剧膨胀。
这种模式叫做命令式UI——你像指挥官一样,一步一步地命令界面:把文字设成什么、把按钮的可见性改为什么、把颜色换成什么。你告诉UI“怎么做”。随着视图数量增加,维护复杂度也在增长。
Jetpack Compose的出现,就是为了从根上解决这个问题。
二、Jetpack Compose是什么
Jetpack Compose是Google为Android打造的现代声明式UI工具包。它用Kotlin语言编写,完全抛弃了XML布局文件,让你用一系列函数来描述界面。
官方对它的定位非常明确:Compose正在取代View工具包。传统View体系已经进入维护模式——只会收到关键的修复,不会有大的功能更新。所有新的Android Studio UI工具、文档、示例代码,都会优先围绕Compose来构建。
这意味着什么?意味着从2026年的视角来看,Compose不再是“可以尝试的新东西”,而是 Android UI开发的默认选择。
Compose的核心思想可以用一句话概括:你只需要描述界面“应该是什么样”,而不用操心“怎么变成这样”。
回到刚才的显示/隐藏文字的例子。用Compose写,大概是这个样子:
@Composable
fun MessageToggle() {
var isVisible by remember { mutableStateOf(true) }
Column(modifier = Modifier.padding(16.dp)) {
if (isVisible) {
Text(text = "你好,世界")
}
Button(onClick = { isVisible = !isVisible }) {
Text(text = if (isVisible) "隐藏" else "显示")
}
}
}
没有XML文件,没有 findViewById,没有手动设置 visibility。你声明了:当 isVisible 为true时,显示这段文字。当用户点击按钮,isVisible 变了,界面自动跟着更新。
这就是声明式UI的核心体验:你只管描述状态和界面的关系,框架负责把界面刷新到正确状态。
三、命令式 vs 声明式:一个生活化的比喻
命令式UI和声明式UI的差别,可以用一个日常场景来理解。
命令式就像你指挥一个司机开车:“往前开200米,左转,直行100米,右转,靠边停。”每一步你都要给出精确的指令。如果路况变了(比如前方施工),你得重新规划每一步。
声明式就像你打开导航,输入目的地,然后说:“我要去这里。”导航自己会算出路线、处理路况变化、在需要的时候重新规划。你只关心 “我要到哪里” ,不关心 “怎么到那里” 。
在传统View体系下,你就是那个不停下指令的指挥者。数据变了,你要手动去更新对应的View;多个View显示同一份数据,你就要确保每一处都更新了。一旦漏掉一处,就会出现界面和数据不一致的Bug。Google的官方文档也明确指出,手动操作视图会增加出错的可能性,而且随着需要更新的视图数量增加,维护复杂度会持续增长。
在Compose的声明式模型下,你只描述一件事: “当状态是A时,界面长这样;当状态是B时,界面长那样。” 状态变了的瞬间,Compose自动完成从状态到界面的映射。你不需要追踪哪些View需要更新,不需要记住上次的状态是什么。
这种思维转变,是学习Compose最需要跨越的门槛。一旦习惯了,你会发现UI代码变得异常简洁和可预测。
四、可组合函数:Compose的“基本粒子”
在Compose的世界里,一切界面都是由 可组合函数 构成的。
可组合函数就是普通的Kotlin函数,只不过它被一个特殊的注解标记了:@Composable。这个注解告诉Compose编译器:“这个函数是用来描述界面的。”
来看一个最简单的可组合函数:
@Composable
fun Greeting(name: String) {
Text(text = "你好,$name!")
}
这个函数做了几件事:
- 接收数据:name 参数,让调用者可以传入不同的名字
- 发射UI:调用 Text() 可组合函数,在界面上显示一段文字
- 不返回任何东西:它描述的是“屏幕上应该出现什么”,而不是“构造一个对象返回给你”
可组合函数有几个重要的特性:
第一,它可以调用其他可组合函数。 Greeting 调用了 Text,而 Text 本身也是一个可组合函数。通过这种嵌套,你可以从最小的UI元素开始,一层一层搭建出复杂的界面。
第二,它应该是“纯”的。 官方文档强调,可组合函数应当是幂等的——同样的输入,应该得到同样的输出,不依赖全局变量,不产生副作用(比如修改外部变量)。这听起来是个限制,但实际上它让Compose能够智能地判断:这个函数的输入没变,那它的输出也不用重新计算,直接复用就行。
第三,函数的命名习惯用大写开头。 比如 Greeting、MessageCard、UserProfile,这跟传统Kotlin函数用小写开头的习惯不同,为的是在代码里一眼就能区分“这是UI组件”和“这是普通逻辑”。
可组合函数最强大的地方在于 组合。你可以把界面拆成一个个小的、独立的可组合函数,每个只负责一小块。小的可以组合成大的,大的可以组合成更大的。就像乐高积木一样,每块积木很简单,但拼在一起可以搭出任何东西。官方文档也特别提到,通过制作小的可复用可组合项,很容易构建起一个应用级别的UI元素库,每个元素独立负责屏幕的一部分,可以单独编辑和测试。
五、为什么说Compose值得学:五个实打实的理由
5.1 代码量大幅减少
刚才的显示/隐藏示例已经很直观了。在传统方式下,你需要一个XML文件加一个Activity/Kotlin文件;在Compose里,一个函数就够了。对于更复杂的界面——比如一个带头像、名字、在线状态、操作按钮的用户卡片——XML可能需要三四十行,Compose可能只需要十几行。
这不是“少写一点”的问题,而是代码组织方式的根本变化。XML和Kotlin逻辑是分开的,你需要在两个文件之间来回跳转来理解一个界面。Compose把布局和逻辑放在同一个函数里,代码的局部性更好,阅读和维护都更轻松。
5.2 状态驱动,告别手动同步
这是最核心的改变。在Compose里,你不需要手动调用 findViewById,不需要记住哪个View绑定了哪个数据。你只需要定义状态,然后说“当状态是这样的时候,界面应该是那样”。
当状态变化时,Compose会自动找出哪些界面依赖了这个状态,只重新执行那些部分。这个过程叫做重组 。你不用操心“哪些View需要更新”,框架帮你做了这件事。
5.3 原生性能,滚动流畅度已追平View
早期版本的Compose在性能上确实和View有一定差距,但这个问题已经基本解决了。根据Google的路线图,从Compose 1.9.0开始,滚动性能(以卡顿为指标)已经与View持平。
Compose通过智能跳过机制来优化性能:如果一个可组合函数的输入参数没有变化,Compose会完全跳过它的重新执行,直接复用之前的UI输出。这种优化在列表滚动等高频场景下效果显著。
5.4 开发工具强大,预览即所得
Android Studio为Compose提供了专门的开发体验。@Preview 注解可以让你在IDE里直接看到UI的渲染效果,不用把应用跑到设备上。配合实时编辑功能,你改一行代码,预览立刻更新。
还有一个很实用的变化:新的Android Studio UI工具只面向Compose构建,传统的布局编辑器和导航编辑器已经不再获得新功能。
5.5 自适应布局:一套代码适配多种设备
Compose在设计之初就考虑了自适应的问题。手机、平板、折叠屏、甚至桌面端的Android应用,Compose都提供了统一的工具来适配不同屏幕尺寸。官方明确表示,Compose是构建自适应应用最简单的方式。
六、Compose的架构分层:了解它的“内功”
你不需要一开始就深入理解Compose的每一层架构,但知道它的分层设计有助于你理解“为什么Compose能做到这些”。
Jetpack Compose不是一个大而全的库,而是由多个模块组装而成的。从底层到上层,主要分为四层。
最底层是Runtime(运行时) 。这一层提供了Compose最核心的机制:remember、mutableStateOf、@Composable 注解、状态追踪等。它管的是“状态怎么存、什么时候重组”这类底层逻辑,跟具体的UI长什么样没有关系。
第二层是UI层。这一层开始涉及界面了,它负责布局节点的管理、Modifier 系统、输入事件处理、自定义布局和绘制。Modifier 是Compose里一个很重要的概念——你可以把它理解成“给一个UI元素附加的各种属性”,比如内边距、背景色、点击事件等。
第三层是Foundation(基础层) 。这一层提供了与设计系统无关的构建块,比如 Row(横向排列)、Column(纵向排列)、LazyColumn(懒加载列表)、手势识别等。如果你只是想要基本的布局能力,Foundation就够了。
最上层是Material层。这一层是Material Design在Compose中的实现,提供了主题系统、按钮、卡片、顶部栏等预制的Material组件。
这个分层设计的精妙之处在于:每一层都建立在下面一层之上,但你可以在任何一层开始构建。 如果你只需要Compose的状态管理能力,可以只用Runtime层;如果你想要完整的Material Design体验,直接用最上层的组件就好。官方强调,Compose的指导原则是提供一系列小而可组合的模块,而不是几个庞大的单体组件。
七、Compose与传统View的对比:一张“大白话”清单
把两种方式放在一起对比,差异会更清楚:
| 界面定义方式 | XML文件定义布局 | Kotlin函数描述界面 |
| 编程范式 | 命令式:手动更新View | 声明式:状态驱动自动更新 |
| 查找视图 | findViewById / ViewBinding | 不需要,直接调用可组合函数 |
| 状态同步 | 手动同步数据和界面 | 自动重组,状态变了界面跟着变 |
| 布局与逻辑 | 分开在两个文件中 | 在同一个函数中 |
| 预览 | 布局编辑器 | @Preview 注解,支持实时编辑 |
| 最小API支持 | 各版本不同 | API 21+(Android 5.0及以上) |
| 组件复用 | 自定义View较复杂 | 可组合函数天然可复用 |
| 当前状态 | 维护模式,仅关键修复 | Compose-first,持续更新 |
关于最小API支持:Compose只需要 API level 21(Android 5.0)及以上即可使用,覆盖面已经非常广。
关于“维护模式”:Google明确表示,View工具包(如 android.widget 包中的 TextView、ListView 等)现在处于维护模式,只会收到高度关键的修复。传统的基于View的Jetpack库也不会获得重大更新。所有新的Android Studio UI工具只面向Compose构建。
八、状态管理:Compose的“引擎”
状态是Compose最核心的概念之一。理解状态,就理解了Compose的“引擎”是怎么工作的。
8.1 一个“不工作”的例子
先看一段看起来合理、但实际不会工作的代码:
@Composable
fun Greeting() {
var expanded = false // 这样写不对!
Column {
Text(text = if (expanded) "展开的内容" else "")
Button(onClick = { expanded = !expanded }) {
Text(if (expanded) "收起" else "展开")
}
}
}
点击按钮,expanded 确实变了,但界面不会更新。原因有两个:
第一,普通的变量赋值不会被Compose追踪。Compose不知道这个变量变了,自然也不会触发重组。
第二,即使Compose追踪了,每次 Greeting 函数被重新执行时,var expanded = false 都会把值重置回 false,状态丢失了。
8.2 mutableStateOf + remember
要让Compose“知道”一个值的变化,需要用 mutableStateOf 来包装它:
val expanded = mutableStateOf(false)
mutableStateOf 创建的是一个可观察的状态对象。当它的 value 发生变化时,所有读取了这个状态的可组合函数都会被标记为“需要重新执行”。
但是光用 mutableStateOf 还不够。因为可组合函数随时可能被重新执行(重组),如果每次执行都创建一个新的 mutableStateOf(false),状态就丢了。所以还需要 remember 来帮忙:
val expanded = remember { mutableStateOf(false) }
remember 的作用是:在首次组合时计算并存储一个值,在后续重组中返回同一个值,不重新计算。
合在一起,正确写法是:
@Composable
fun Greeting() {
var expanded by remember { mutableStateOf(false) }
Column {
if (expanded) {
Text(text = "展开的内容")
}
Button(onClick = { expanded = !expanded }) {
Text(if (expanded) "收起" else "展开")
}
}
}
这里用了Kotlin的 by 委托语法,读和写 expanded 就像操作普通变量一样,实际上底层是在操作 MutableState 的 value 属性。
8.3 状态提升:让状态“住”在合适的地方
有时候,一个状态不只是一个可组合函数内部的事。比如,父组件和子组件可能都需要读写同一个状态。
Compose的解决办法叫状态提升 :把状态从子组件“提升”到它们的共同父组件中,子组件通过参数接收状态值,通过回调函数通知父组件状态应该怎么变。
@Composable
fun Parent() {
var text by remember { mutableStateOf("") }
Column {
Child(
value = text,
onValueChange = { text = it }
)
Text(text = "你输入了:$text")
}
}
@Composable
fun Child(
value: String,
onValueChange: (String) -> Unit
) {
TextField(
value = value,
onValueChange = onValueChange
)
}
Child 不持有状态,它只负责“显示”和“通知”。状态由 Parent 持有。这种模式叫做单向数据流:数据从父流向子,事件从子流回父。官方文档指出,由于可组合函数接受状态并公开事件(如 TextField 接受值并公开 onValueChange 回调),单向数据流模式天然适用于Jetpack Compose。
状态提升的好处是:状态的来源变得清晰可追溯,测试起来也更容易——你不需要启动整个UI,只需要给函数传入不同的参数就能测试它的行为。
九、从零搭建一个Compose项目
讲了这么多概念,是时候动手了。
9.1 环境要求
- Android Studio:建议使用最新稳定版。Compose的开发体验高度依赖IDE工具链。
- Kotlin:Compose完全基于Kotlin,需要确保项目已经配置了Kotlin支持。
- 最小API:API 21(Android 5.0)及以上。
9.2 创建项目
打开Android Studio,在欢迎界面点击 New Project(如果已经打开了项目,选择 File > New > New Project)。在模板列表中选择 Empty Activity。在配置界面中,确保语言选择 Kotlin——Jetpack Compose只支持Kotlin。
创建完成后,Android Studio会自动帮你配置好Compose所需的Gradle依赖和编译器插件。你不需要手动添加任何东西。
9.3 看懂自动生成的代码
项目创建后,打开 MainActivity.kt,你会看到类似这样的代码:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyAppTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
Greeting(
name = "Android",
modifier = Modifier.padding(innerPadding)
)
}
}
}
}
}
@Composable
fun Greeting(name: String, modifier: Modifier = Modifier) {
Text(
text = "Hello $name!",
modifier = modifier
)
}
@Preview(showBackground = true)
@Composable
fun GreetingPreview() {
MyAppTheme {
Greeting("Android")
}
}
这段代码里有几个关键点值得注意:
setContent :这是从传统Activity世界进入Compose世界的“入口”。在 setContent 的lambda里,你写的一切都是可组合函数。
Scaffold :提供了一个Material Design的基本页面结构。innerPadding 用来避免内容被状态栏、导航栏等系统UI遮挡。
@Preview :这个注解让 GreetingPreview 函数可以在Android Studio的预览面板中渲染出来。你不需要把应用跑到设备上,就能看到 Greeting 组件长什么样。这是Compose开发中非常高频使用的功能。
Modifier :你看到 Greeting 函数接收了一个 modifier: Modifier = Modifier 参数。这是Compose的惯例——每个可组合函数都应该接受一个 Modifier 参数,这样调用者可以从外部给组件添加各种修饰(内边距、尺寸、点击事件等)。
9.4 改一行代码试试
把 Greeting 里的文字改掉:
Text(text = "你好,Compose!")
保存后,预览面板会立刻更新。这就是Compose开发最日常的节奏:写代码,看预览,改代码,预览更新。不需要编译、安装、启动应用。
十、Compose的现状与未来
10.1 现状:Compose-first
2026年的Android开发已经进入 Compose-first 时代。Google明确表示:
- 新工具只面向Compose:所有新的Android Studio UI工具都只为Compose构建。
- 文档和教程以Compose为主:官方的文档、codelab、示例项目都优先围绕Compose展开。
- View进入维护模式:传统View组件只会收到关键修复,不会有新功能。
但这不意味着View会立刻消失。Google也承诺会在一段时间内继续支持传统View,并提供互操作API,让开发者可以按自己的节奏逐步迁移。
10.2 迁移路径:渐进式采用
如果你手上有一个基于XML和View的现有项目,不需要一次性全部重写。Compose支持与View的双向互操作:
- 在View中使用Compose:可以通过 ComposeView 把Compose界面嵌入到XML布局中。
- 在Compose中使用View:可以通过 AndroidView 可组合函数把传统的View嵌入到Compose界面中。
推荐的迁移策略是 “Compose Island” :从新功能或者某个独立的页面开始,用Compose实现,作为一个“岛屿”嵌入到现有的View体系中。随着时间推移,岛屿越来越多,最终完成迁移。
10.3 路线图上的亮点
根据Google公布的Compose路线图,未来值得关注的方向包括:
- 性能持续优化:矢量缓存改进、模糊效果改进、高级图形效果
- 文本和输入增强:多样式文本编辑、文本选择API改进、自适应文字大小
- 动画和导航:更高级的动画支持、共享元素过渡
- 生成式AI与UI开发实验:将AI能力融入UI开发流程
10.4 现在就是学习Compose的最佳时机
如果你还在犹豫“要不要学Compose”,答案已经很清楚了:要。
不是因为Compose“新”,而是因为它已经是Android UI开发的主流方向。新项目默认用Compose,新工具优先支持Compose,新文档围绕Compose编写。继续只用传统View体系,意味着你在使用一个处于维护模式的技术栈。
而且,学Compose的门槛并不高。它用Kotlin,这是大多数Android开发者已经熟悉的语言。它的核心概念——可组合函数、状态、重组——数量不多,而且逻辑自洽。一旦理解了“声明式思维”,后面的路会越来越顺。
十一、本课小结
这一课我们聊了这些问题:
- 为什么需要Compose:传统命令式UI在复杂界面下的维护成本越来越高,声明式UI是行业的演进方向。
- Compose是什么:一个声明式的、基于Kotlin的UI工具包,你描述“界面应该是什么样”,框架负责“怎么变成这样”。
- 可组合函数:Compose的基本构建单元,用 @Composable 注解标记的普通函数,接收数据、发射UI。
- 架构分层:Runtime → UI → Foundation → Material,从底层机制到上层组件,每一层都可以独立使用。
- 状态管理:mutableStateOf 创建可观察状态,remember 在重组间保留状态,状态提升让状态在组件树中流动。
- 环境搭建:用Android Studio创建Empty Activity项目,@Preview 可以实时预览,Modifier 用来修饰组件。
- 现状与未来:Compose-first已经成为Android开发的既定方向,View体系逐步进入维护模式,但互操作API保证了渐进式迁移的可行性。
如果这一课你只记住一件事,希望是这个:在Compose里,你不再需要告诉界面“怎么变”,只需要告诉它“是什么”。 状态变了,界面自己会跟上。
下一课,我们会正式动手写Compose代码——从最基本的布局开始,逐步构建出真实的界面。
网硕互联帮助中心



评论前必须登录!
注册