为什么选择 Jetpack Compose

Jetpack Compose 是 Google 官方的声明式 UI 工具包,用 Kotlin 写界面,替代传统的 XML 布局。核心区别:

传统 View 体系 Jetpack Compose
XML 写布局 纯 Kotlin 声明 UI
数据变化手动 findViewById 更新 状态变化 UI 自动重组
命令式(告诉系统”怎么改”) 声明式(告诉系统”长什么样”)

一、创建项目

打开 Android Studio,选择 New Project → Empty Activity,语言选 Kotlin,最低 SDK 建议 API 24+。新版 Android Studio 会自动引入 Compose 依赖。

关键依赖(app/build.gradle.kts):

1
2
3
4
5
6
dependencies {
implementation(platform("androidx.compose:compose-bom:2024.09.03"))
implementation("androidx.compose.ui:ui")
implementation("androidx.compose.material3:material3")
implementation("androidx.activity:activity-compose:1.9.2")
}

二、第一个 Composable 页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.example.myapp

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApp()
}
}
}

@Composable
fun MyApp() {
MaterialTheme {
GreetingScreen()
}
}

@Composable
fun GreetingScreen() {
// remember:状态在重组时保留;mutableStateOf:状态变化触发重组
var count by remember { mutableStateOf(0) }

Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "点击次数:$count",
style = MaterialTheme.typography.headlineMedium
)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { count++ }) {
Text("点我")
}
}
}

几个关键点:

  • @Composable 标记可组合函数,UI 全由这些函数组成;
  • remember { mutableStateOf(...) } 是 Compose 的状态管理核心,状态变了,使用它的 UI 自动重组;
  • Column / Row / Box 是三大布局容器,Modifier 链式设置尺寸、边距、对齐。

三、状态提升与回调

子组件不应持有全局状态,把状态”提升”到父组件,通过参数 + 回调传递:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Composable
fun CounterScreen() {
var count by remember { mutableStateOf(0) }

Column(horizontalAlignment = Alignment.CenterHorizontally) {
CounterDisplay(count = count)
CounterButton(onIncrement = { count++ })
}
}

@Composable
fun CounterDisplay(count: Int) {
Text("当前值:$count", style = MaterialTheme.typography.titleLarge)
}

@Composable
fun CounterButton(onIncrement: () -> Unit) {
Button(onClick = onIncrement) {
Text("+1")
}
}

四、列表:LazyColumn

列表用 LazyColumn(对应 RecyclerView),只渲染可见项,性能好:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Composable
fun TodoList(todos: List<String>) {
LazyColumn(
modifier = Modifier.fillMaxSize(),
contentPadding = PaddingValues(16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
items(todos.size) { index ->
Card(modifier = Modifier.fillMaxWidth()) {
Text(
text = todos[index],
modifier = Modifier.padding(16.dp)
)
}
}
}
}

items 也支持 items(todos) 传数据列表,配合 key 参数提供稳定 id:

1
2
3
items(items = todos, key = { it.id }) { todo ->
TodoItem(todo)
}

五、主题配置

Compose 的主题基于 MaterialTheme 的三个维度:colorScheme、typography、shapes。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private val LightColors = lightColorScheme(
primary = Color(0xFF3F51B5),
secondary = Color(0xFFFF9800)
)

private val DarkColors = darkColorScheme(
primary = Color(0xFF7986CB)
)

@Composable
fun MyAppTheme(
darkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
MaterialTheme(
colorScheme = if (darkTheme) DarkColors else LightColors,
typography = Typography(),
content = content
)
}

isSystemInDarkTheme() 自动跟随系统深色模式。

六、@Preview 实时预览

Compose 支持不跑模拟器直接在 IDE 里预览:

1
2
3
4
5
6
7
@Preview(showBackground = true, showSystemUi = true)
@Composable
fun GreetingScreenPreview() {
MyAppTheme {
GreetingScreen()
}
}

常见坑

  1. remember 与 rememberSaveable:旋转屏幕后 remember 状态会丢,需要跨配置保留时用 rememberSaveable;
  2. 重组范围过大:尽量把状态往下传、把不变的 Composable 用 Modifier 或其他手段隔离,减少不必要的重组;
  3. 协程:异步操作在 LaunchedEffect 里做,不要直接在 Composable 里 Thread.sleep 之类的阻塞操作。

总结

Compose 的核心思维转变是”状态驱动 UI”:先声明状态,再声明状态到 UI 的映射。熟练掌握 remember + mutableStateOf、LazyColumn、状态提升这三板斧,就能开始写业务页面了。下一步可以学 Navigation 导航和 ViewModel 架构组件。