云计算百科
云计算领域专业知识百科平台

【Jetpack Compose娓娓道来】第1课:从介绍开始

一、一个让无数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 + ViewJetpack Compose
界面定义方式 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代码——从最基本的布局开始,逐步构建出真实的界面。

赞(0)
未经允许不得转载:网硕互联帮助中心 » 【Jetpack Compose娓娓道来】第1课:从介绍开始
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!