Kotlin + Jetpack Compose 现代 Android 开发实战
认识 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 项目
- 打开 Android Studio,点击 “New Project”。
- 选择 “Empty Activity” 模板,语言选择 Kotlin,最低 SDK 选择 API 21(Compose 完全支持 API 21+)。
- 勾选 “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
apply、let、also 等能让 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):精确尺寸。padding、offset、width、height。weight:在Row或Column中按权重分配空间(需要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 组件
Button、OutlinedButton、TextButtonTextField、OutlinedTextFieldCard、ElevatedCardScaffold:页面骨架,提供 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)。只需传入 items 或 itemsIndexed。
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() 和 onNodeWithText、performClick 等语义匹配器:
@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+)。 - 避免过度重组:使用
remember、derivedStateOf、稳定参数和 key。 - 测量性能:使用 Android Studio 的 Compose 调试工具,查看重组次数和时间。
Kotlin 与 Jetpack Compose 的组合让 Android 开发回归到用简洁语言描述界面的本质。从简单的计数器到大面积列表,再到复杂的状态管理、导航和动画,你都有了应对的手段。下一步,可以尝试连接网络数据、使用 Room 本地存储,或者深入探索自定义布局与画布绘制。享受用代码创造界面的乐趣吧!