Kotlin: Kotlin Android基础详解
最后更新:2026-08-26
Android 开发已全面拥抱 Kotlin——Jetpack Compose 用 Kotlin DSL 构建声明式 UI,ViewModel + StateFlow 管理响应式状态,Room + 协程简化数据层。Charlie 用 Kotlin 构建订单看板 Android 端。
1. 你将学到
- Activity / Fragment 生命周期与 Kotlin 集成
- Jetpack Compose:声明式 UI + Kotlin DSL
- ViewModel + StateFlow:响应式状态管理
- Room 数据库: / + 协程
- Charlie 实战:Android 端订单看板
2. 一个开发者的真实故事
(1) 痛点:命令式 UI 的状态同步地狱
Alice 用 XML + RecyclerView 开发订单列表,每个状态变化都要手动更新 UI:数据变了要 ,加载中要 ——10 个状态有 20+ 行 UI 同步代码。
(2) Compose 声明式 UI 的解法
KOTLIN
// XML + RecyclerView: imperative, error-prone
// recyclerView.adapter.notifyDataSetChanged()
// Compose: declarative, automatic
@Composable
fun OrderList(orders: List`<Order>`) {
LazyColumn {
items(orders) { order ->
OrderCard(order) // UI automatically reflects data changes
}
}
}
Compose 是声明式的——UI 是状态的函数,数据变了 UI 自动更新,无需手动同步。
3. Activity 生命周期
(1) 生命周期回调
KOTLIN
class OrderActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
OrderScreen()
}
}
override fun onResume() {
super.onResume()
// Refresh data when activity comes to foreground
}
override fun onPause() {
super.onPause()
// Save draft data
}
}
(2) 生命周期状态图
stateDiagram-v2
[*] --> Created: onCreate()
Created --> Started: onStart()
Started --> Resumed: onResume()
Resumed --> Started: onPause()
Started --> Created: onStop()
Created --> [*]: onDestroy()
Started --> Resumed: onResume()
(3) 生命周期回调对比
| 回调 | 触发时机 | 典型操作 |
|---|---|---|
| Activity 创建 | 初始化 UI、ViewModel | |
| 可见但不可交互 | 注册监听器 | |
| 获得焦点 | 开始动画、刷新数据 | |
| 失去焦点 | 暂停动画、保存草稿 | |
| 不可见 | 释放资源 | |
| 销毁 | 清理资源 |
4. Jetpack Compose
(1) Composable 函数
KOTLIN
@Composable
fun OrderCard(order: Order) {
Card(
modifier = Modifier.fillMaxWidth().padding(8.dp),
elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)
) {
Row(
modifier = Modifier.padding(16.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Column {
Text(text = order.id, style = MaterialTheme.typography.titleMedium)
Text(text = order.customer, style = MaterialTheme.typography.bodyMedium)
}
Text(
text = "\$${order.total} USD",
style = MaterialTheme.typography.titleLarge
)
}
}
}
(2) 列表与状态
KOTLIN
@Composable
fun OrderListScreen(viewModel: OrderViewModel = viewModel()) {
val orders by viewModel.orders.collectAsState()
val isLoading by viewModel.isLoading.collectAsState()
if (isLoading) {
CircularProgressIndicator()
} else {
LazyColumn {
items(orders) { order ->
OrderCard(order)
}
}
}
}
(3) Compose 渲染管线
flowchart TD
A[State Change] --> B[Composition<br/>Run @Composable functions]
B --> C[Layout<br/>Measure and position]
C --> D[Drawing<br/>Render to canvas]
D --> E[UI Updated]
(4) XML vs Compose 对比
| 维度 | XML + View | Jetpack Compose |
|---|---|---|
| 范式 | 命令式 | 声明式 |
| 语言 | XML + Kotlin | 纯 Kotlin |
| 状态同步 | 手动 | 自动 |
| 代码量 | 多(XML + Adapter + ViewHolder) | 少(@Composable) |
| 预览 | 需运行 | IDE 实时预览 |
| 学习曲线 | 中等 | 中等(新范式) |
5. ViewModel + StateFlow
(1) ViewModel
KOTLIN
class OrderViewModel : ViewModel() {
private val _orders = MutableStateFlow<List`<Order>`>(emptyList())
val orders: StateFlow<List`<Order>`> = _orders.asStateFlow()
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow`<Boolean>` = _isLoading.asStateFlow()
fun loadOrders() {
viewModelScope.launch {
_isLoading.value = true
try {
_orders.value = orderRepository.findAll()
} finally {
_isLoading.value = false
}
}
}
}
(2) StateFlow vs LiveData
| 维度 | LiveData | StateFlow |
|---|---|---|
| 初始值 | 无 | 必须有 |
| 协程支持 | 需转换 | 原生 |
| 线程 | 主线程 | 任意线程 |
| 生命周期 | 感知 | 需 |
| 推荐度 | 旧代码 | 新项目 |
6. Room 数据库
(1) Entity + Dao
KOTLIN
@Entity(tableName = "orders")
data class OrderEntity(
@PrimaryKey val id: String,
val total: Double,
val status: String,
val customer: String,
val createdAt: Long = System.currentTimeMillis()
)
@Dao
interface OrderDao {
@Query("SELECT * FROM orders ORDER BY createdAt DESC")
fun getAllOrders(): Flow<List`<OrderEntity>`>
@Query("SELECT * FROM orders WHERE id = :id")
suspend fun getById(id: String): OrderEntity?
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insert(order: OrderEntity)
@Delete
suspend fun delete(order: OrderEntity)
}
(2) Room 组件
| 组件 | 注解 | 职责 |
|---|---|---|
| Entity | 数据库表映射 | |
| Dao | 数据访问操作 | |
| Database | 数据库入口 |
7. 完整示例:Android 订单看板
KOTLIN
// ============================================
// OrderProcessor - Android Order Dashboard
// Feature: Compose UI + ViewModel + StateFlow
// ============================================
// --- Domain ---
data class Order(val id: String, val total: Double, val status: String, val customer: String)
// --- ViewModel ---
class OrderViewModel : ViewModel() {
private val _orders = MutableStateFlow<List`<Order>`>(emptyList())
val orders: StateFlow<List`<Order>`> = _orders.asStateFlow()
private val _isLoading = MutableStateFlow(false)
val isLoading: StateFlow`<Boolean>` = _isLoading.asStateFlow()
init {
loadOrders()
}
fun loadOrders() {
viewModelScope.launch {
_isLoading.value = true
delay(500) // Simulate network
_orders.value = listOf(
Order("ORD-001", 299.99, "CONFIRMED", "Alice"),
Order("ORD-002", 15_000.00, "PENDING", "Bob"),
Order("ORD-003", 2_500.00, "SHIPPED", "Charlie"),
Order("ORD-004", 8_900.00, "CONFIRMED", "Bob"),
Order("ORD-005", 45.50, "CANCELLED", "Alice")
)
_isLoading.value = false
}
}
fun totalRevenue(): Double = _orders.value
.filter { it.status != "CANCELLED" }
.sumOf { it.total }
}
// --- Compose UI (Conceptual - requires Android runtime) ---
// @Composable
// fun OrderScreen(viewModel: OrderViewModel = viewModel()) {
// val orders by viewModel.orders.collectAsState()
// val isLoading by viewModel.isLoading.collectAsState()
//
// Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
// Text("Order Dashboard", style = MaterialTheme.typography.headlineMedium)
// Text("Revenue: \$${viewModel.totalRevenue()} USD", style = MaterialTheme.typography.titleLarge)
//
// if (isLoading) {
// CircularProgressIndicator()
// } else {
// LazyColumn {
// items(orders) { order -> OrderCard(order) }
// }
// }
// }
// }
// --- JVM Demo (simulating the ViewModel logic) ---
fun main() {
val viewModel = OrderViewModel()
// Simulate observing state
Thread.sleep(1000) // Wait for loading
println("=== Android Order Dashboard ===")
println("Revenue: \$${viewModel.totalRevenue()} USD")
println("Loading: ${viewModel.isLoading.value}")
viewModel.orders.value.forEach { order ->
val icon = when (order.status) {
"CONFIRMED" -> "✅"
"PENDING" -> "⏳"
"SHIPPED" -> "📦"
"CANCELLED" -> "❌"
else -> "?"
}
println(" $icon ${order.id}: \$${order.total} USD (${order.customer}) [${order.status}]")
}
}
输出:
TEXT
📖 仅展示
=== Android Order Dashboard ===
Revenue: $26699.99 USD
Loading: false
✅ ORD-001: $299.99 USD (Alice) [CONFIRMED]
⏳ ORD-002: $15000.0 USD (Bob) [PENDING]
📦 ORD-003: $2500.0 USD (Charlie) [SHIPPED]
✅ ORD-004: $8900.0 USD (Bob) [CONFIRMED]
❌ ORD-005: $45.5 USD (Alice) [CANCELLED]
❓ 常见问题
Q 必须用 Compose 吗?还能用 XML 吗?
A 可以继续用 XML,但 Google 推荐 Compose 作为新项目默认方案。Compose 和 XML 可以混合使用( 在 XML 中嵌入 Compose)。
Q ViewModel 和 Presenter 有什么区别?
A ViewModel 在配置变更(屏幕旋转)时不会被销毁,数据自动保留。Presenter 在配置变更时需要手动保存恢复。
Q StateFlow 和 SharedFlow 怎么选?
A StateFlow 用于持有状态(必须有初始值,去重),SharedFlow 用于事件流(可多播,无初始值)。UI 状态用 StateFlow,一次性事件用 SharedFlow。
Q Room 支持协程吗?
A 支持。Dao 的 suspend 函数自动在 Room 的线程池中执行,返回 Flow 的查询自动在数据变化时重新发射。
Q Compose 的性能如何?
A Compose 使用智能重组(只重绘变化的 Composable),性能接近手写 View。避免在 Composable 中做计算——用 和 缓存。
Q 如何在 Compose 中处理导航?
A 使用 + 定义导航图, 跳转。类型安全导航在 Compose 1.0+ 可用。
📖 小节
- Android 开发已全面 Kotlin 化,Jetpack Compose 是 UI 新范式
- Compose 声明式 UI:UI = f(State),数据变了 UI 自动更新
- ViewModel + StateFlow 管理响应式 UI 状态,配置变更安全
- Room + 协程 + Flow 构建响应式数据层
- Compose 用 Kotlin DSL 构建组件树,比 XML 更简洁
- Activity 生命周期仍是 Android 基础,但 Compose 减少了与生命周期的直接交互
📝 作业
- 基础题(难度⭐):创建一个 Compose 函数,显示 "Hello, $name!"。提示:
- 进阶题(难度⭐⭐):用 ViewModel + StateFlow 实现一个计数器,Compose UI 实时显示计数。提示: +
- 挑战题(难度⭐⭐⭐):实现完整的订单列表 Compose UI:LazyColumn 展示订单、下拉刷新、点击跳转详情。提示: +