Kotlin: Kotlin Android基础详解

最后更新:2026-08-26

Android 开发已全面拥抱 Kotlin——Jetpack Compose 用 Kotlin DSL 构建声明式 UI,ViewModel + StateFlow 管理响应式状态,Room + 协程简化数据层。Charlie 用 Kotlin 构建订单看板 Android 端。

1. 你将学到


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) 生命周期状态图

100%
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 渲染管线

100%
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+ 可用。

📖 小节


📝 作业

  1. 基础题(难度⭐):创建一个 Compose 函数,显示 "Hello, $name!"。提示:
  2. 进阶题(难度⭐⭐):用 ViewModel + StateFlow 实现一个计数器,Compose UI 实时显示计数。提示: +
  3. 挑战题(难度⭐⭐⭐):实现完整的订单列表 Compose UI:LazyColumn 展示订单、下拉刷新、点击跳转详情。提示: +

← 上一课 | 下一课 →

Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏