Kotlin + Jetpack Compose 现代 Android 开发实战

FreeGuideOnline 最新 2026-06-12

认识 Kotlin 与 Jetpack Compose

现代 Android 开发已经全面拥抱声明式 UI 与简洁的 Kotlin 语言。Jetpack Compose 是 Google 推出的原生 Android UI 工具包,它彻底改变了我们构建界面的方式:不需要 XML,所有界面都用 Kotlin 代码描述,UI 会自动响应状态变化。本教程将带你从零开始,掌握 Kotlin + Jetpack Compose 的核心知识,构建出美观、可维护的现代 Android 应用。

为什么选择 Kotlin + Compose

  • 更少的代码:Kotlin 语言设计现代、简洁,Compose 用声明式写法消除了大量样板代码。
  • 直观的状态管理:界面由状态驱动,状态改变时 UI 自动重组,无需手动刷新视图。
  • 原生性能:Compose 直接编译为 Android 原生绘图指令,拥有接近原生 View 体系的性能。
  • 强大的工具支持:Android Studio 提供实时预览、交互式调试和丰富的模板。
  • 无缝互操作:可以逐步采用,在现有 View 体系中嵌入 Compose,或反过来。

环境搭建与项目创建

安装 Android Studio

确保使用最新稳定版 Android Studio(Hedgehog 或更新版本),它内置了 Compose 模板和预览工具。下载时选择包含 Android SDK 的版本。

新建 Compose 项目

  1. 打开 Android Studio,点击 “New Project”。
  2. 选择 “Empty Activity” 模板,语言选择 Kotlin,最低 SDK 选择 API 21(Compose 完全支持 API 21+)。
  3. 勾选 “Use Jetpack Compose”,点击 Finish。

项目会自动添加必要的依赖,build.gradle.kts(模块级)中包含:

android {
    buildFeatures {
        compose = true
    }
    composeOptions {
        kotlinCompilerExtensionVersion = "1.5.4" // 使用与 Kotlin 匹配的版本
    }
}

dependencies {
    implementation(platform("androidx.compose:compose-bom:2024.02.00"))
    implementation("androidx.compose.ui:ui")
    implementation("androidx.compose.material3:material3")
    implementation("androidx.compose.ui:ui-tooling-preview")
    debugImplementation("androidx.compose.ui:ui-tooling")
}

建议使用 BOM 统一管理 Compose 版本,避免版本冲突。

了解 Compose 入口

MainActivity 中的 setContent 是 Compose 的入口点,所有界面都在这里组合。默认代码类似于:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            MyAppTheme {
                Surface {
                    Greeting("Android")
                }
            }
        }
    }
}

@Composable
fun Greeting(name: String) {
    Text(text = "Hello, $name!")
}

@Composable 注解标记了可组合函数,它们是构建 UI 的基本单元。

Kotlin 基础速览(为 Compose 铺垫)

即使你熟悉其他语言,也需要关注 Kotlin 中与 Compose 紧密相关的特性。

数据类与默认参数

data class Message(val author: String, val body: String, val timestamp: Long = System.currentTimeMillis())

数据类自动生成 equals()hashCode()toString()copy(),非常适合用作 UI 状态。

高阶函数与 Lambda

Compose 大量使用高阶函数来传递点击、滚动等事件。例如:

@Composable
fun MyButton(onClick: () -> Unit) {
    Button(onClick = onClick) {
        Text("点击我")
    }
}

作用域函数与尾随 Lambda

applyletalso 等能让 Compose 代码更清晰:

var text by remember { mutableStateOf("") }

TextField(
    value = text,
    onValueChange = { text = it },
    label = { Text("输入内容") }
)

状态与 by 委托

mutableStateOf 返回一个可观察状态对象,结合 by 委托可以直接像普通变量一样使用,赋值时会触发 UI 重组。remember 确保状态在重组时不被重置。

Compose 核心思维:声明式 UI 与状态

声明式 vs 命令式

传统的 Android View 是命令式的:你一步步告诉系统如何创建和修改视图。而 Compose 是声明式的:你描述给定状态下界面应该长什么样,Compose 负责在状态变化时高效更新。

状态提升是核心模式:将状态移到更高层级的可组合项,使得组件可复用且易测试。

@Composable
fun CounterScreen() {
    var count by remember { mutableStateOf(0) }
    Column(horizontalAlignment = Alignment.CenterHorizontally) {
        Text("计数: $count", style = MaterialTheme.typography.headlineMedium)
        Button(onClick = { count++ }) {
            Text("增加")
        }
    }
}

重组与智能跳过

当状态变化时,Compose 会重新执行那些读取了该状态的可组合函数,这一过程叫“重组”。Compose 通过位置记忆和类型比较,只更新必要的部分,性能非常高。因此不必担心不必要的重组。

基础布局组件

Column、Row 与 Box

  • Column:垂直排列子项。
  • Row:水平排列子项。
  • Box:子项堆叠,类似 FrameLayout。
Column(
    modifier = Modifier.fillMaxSize().padding(16.dp),
    verticalArrangement = Arrangement.SpaceEvenly,
    horizontalAlignment = Alignment.CenterHorizontally
) {
    Text("上方文本")
    Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
        Button(onClick = {}) { Text("按钮1") }
        Button(onClick = {}) { Text("按钮2") }
    }
}

Modifier:装饰与行为

Modifier 是所有 Composable 都接受的参数,用于设置大小、内边距、背景、点击、滚动等。Modifier 是有顺序的,链式调用时注意先后顺序。

Text(
    text = "可点击文本",
    modifier = Modifier
        .background(Color.Cyan, shape = RoundedCornerShape(8.dp))
        .padding(16.dp)
        .clickable { /* 处理点击 */ }
)

常用的布局修饰符

  • fillMaxSize()fillMaxWidth()fillMaxHeight():填充可用空间。
  • size(width, height):精确尺寸。
  • paddingoffsetwidthheight
  • weight:在 RowColumn 中按权重分配空间(需要 Modifier.weight(1f))。

Material3 设计系统

Compose 集成了 Material Design 3,提供配色、字体和形状样式的统一管理。

主题与颜色

项目创建时带有 Theme.kt 文件,定义了色彩方案。更改颜色只需修改 MaterialTheme.colorScheme 或使用动态配色(Android 12+)。

MaterialTheme(
    colorScheme = lightColorScheme(
        primary = Color(0xFF6200EE),
        onPrimary = Color.White,
        // ...
    )
) {
    // 应用内容
}

在 Composable 中直接使用主题颜色:MaterialTheme.colorScheme.primary

常用 Material3 组件

  • ButtonOutlinedButtonTextButton
  • TextFieldOutlinedTextField
  • CardElevatedCard
  • Scaffold:页面骨架,提供 TopAppBar、BottomBar、FloatingActionButton 等。
  • NavigationBar / NavigationRail

示例:带底部导航的 Scaffold

Scaffold(
    topBar = { TopAppBar(title = { Text("主页") }) },
    bottomBar = {
        NavigationBar {
            NavigationBarItem(selected = false, onClick = {}, icon = { Icon(Icons.Default.Home, "主页") }, label = { Text("主页") })
            NavigationBarItem(selected = true, onClick = {}, icon = { Icon(Icons.Default.Favorite, "收藏") }, label = { Text("收藏") })
        }
    }
) { innerPadding ->
    // 内容区,应用 innerPadding 避免被系统栏遮挡
    Column(modifier = Modifier.padding(innerPadding)) {
        Text("内容区域")
    }
}

列表与懒加载

LazyColumn 与 LazyRow

当数据量较大时,使用 LazyColumn 实现高效的纵向列表(类似 RecyclerView)。只需传入 itemsitemsIndexed

data class Person(val name: String, val age: Int)

@Composable
fun PersonList(persons: List<Person>) {
    LazyColumn {
        items(persons, key = { it.name }) { person ->
            Text(text = "${person.name}, ${person.age}岁", modifier = Modifier.padding(16.dp))
        }
    }
}

key 参数帮助 Compose 唯一标识项目,实现增量更新和动画。

优化列表性能

  • 使用 contentType 区分不同视图类型。
  • 避免在 items 内部使用状态变量(会让每个项目都成为独立状态)。
  • 善用 derivedStateOf 和稳定的键。

状态管理进阶

使用 ViewModel 与 StateFlow

将业务逻辑和 UI 状态放在 ViewModel 中,通过 StateFlow 暴露,然后在 Compose 中收集为 Compose 状态。

class MainViewModel : ViewModel() {
    private val _uiState = MutableStateFlow(MainUiState())
    val uiState: StateFlow<MainUiState> = _uiState.asStateFlow()

    fun updateName(newName: String) {
        _uiState.update { it.copy(name = newName) }
    }
}

data class MainUiState(val name: String = "")

在 Composable 中收集:

val uiState by viewModel.uiState.collectAsStateWithLifecycle()
TextField(
    value = uiState.name,
    onValueChange = viewModel::updateName
)

collectAsStateWithLifecycle() 来自 lifecycle-runtime-compose 库,符合生命周期安全。

处理副作用

Compose 中的副作用包括网络请求、数据库操作等,应放在 LaunchedEffect 或手动协程作用域中,避免在组合过程中执行。

LaunchedEffect(key1 = userId) {
    // 每当 userId 改变,重新加载
    val data = repository.loadUser(userId)
    _uiState.update { it.copy(user = data) }
}

导航:构建多页面应用

添加导航依赖

build.gradle.kts 中添加:

implementation("androidx.navigation:navigation-compose:2.7.7")

设置 NavHost

val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
    composable("home") { HomeScreen(onNavigate = { navController.navigate("detail/$it") }) }
    composable("detail/{id}", arguments = listOf(navArgument("id") { type = NavType.StringType })) { backStackEntry ->
        val id = backStackEntry.arguments?.getString("id") ?: ""
        DetailScreen(id = id)
    }
}

参数传递与类型安全

推荐使用 Kotlin Serialization 或手动定义参数类型。对于复杂对象,通过 JSON 传递或使用共享 ViewModel。

动画与交互

Compose 内置丰富的动画 API,让界面生动起来。

简单动画

var visible by remember { mutableStateOf(false) }
val alpha by animateFloatAsState(if (visible) 1f else 0f, label = "alpha")

Box(modifier = Modifier.size(100.dp).graphicsLayer(alpha = alpha).background(Color.Red))

可见性与内容动画

AnimatedVisibility 可以为出现/消失提供动画:

AnimatedVisibility(visible = visible) {
    Text("Hello, Compose!")
}

列表动画

LazyColumn 的项目添加插入/删除动画可以使用 animateItemPlacement() 修饰符。

LazyColumn {
    items(items, key = { it.id }) {
        Text(it.text, modifier = Modifier.animateItemPlacement())
    }
}

与现有 Android 生态协作

在现有项目中集成 Compose

在已有的基于 View 的布局文件中添加 ComposeView

<androidx.compose.ui.platform.ComposeView
    android:id="@+id/compose_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content" />

在代码中设置内容:

findViewById<ComposeView>(R.id.compose_view).setContent {
    MyComposable()
}

在 Compose 中使用 View(AndroidView)

某些复杂 View(如 MapView、WebView)尚未 Compose 化,使用 AndroidView 包装:

AndroidView(factory = { context ->
    WebView(context).apply {
        settings.javaScriptEnabled = true
        loadUrl("https://example.com")
    }
}, modifier = Modifier.fillMaxSize())

测试 Compose 界面

Compose 提供了独立的测试库,无需启动完整 Activity 即可测试 UI 逻辑。

依赖配置

androidTestImplementation("androidx.compose.ui:ui-test-junit4")
debugImplementation("androidx.compose.ui:ui-test-manifest")

编写测试

使用 createComposeRule()onNodeWithTextperformClick 等语义匹配器:

@get:Rule
val composeTestRule = createComposeRule()

@Test
fun counterIncrementsOnClick() {
    composeTestRule.setContent { CounterScreen() }
    composeTestRule.onNodeWithText("计数: 0").assertExists()
    composeTestRule.onNodeWithText("增加").performClick()
    composeTestRule.onNodeWithText("计数: 1").assertExists()
}

发布建议与优化

  • 开启 isMinifyEnabled = true 和资源缩减。
  • 使用 Compose Compiler 的性能配置:在 build.gradle.kts 中配置 composeCompiler { enableStrongSkipping = true }(Compose Compiler 1.5.4+)。
  • 避免过度重组:使用 rememberderivedStateOf、稳定参数和 key。
  • 测量性能:使用 Android Studio 的 Compose 调试工具,查看重组次数和时间。

Kotlin 与 Jetpack Compose 的组合让 Android 开发回归到用简洁语言描述界面的本质。从简单的计数器到大面积列表,再到复杂的状态管理、导航和动画,你都有了应对的手段。下一步,可以尝试连接网络数据、使用 Room 本地存储,或者深入探索自定义布局与画布绘制。享受用代码创造界面的乐趣吧!