本章深入 Kotlin 高级语言特性:协程原理、Flow 冷热流、委托属性实现、DSL 设计、以及 Android Binder 通信机制、Handler/Looper 消息队列、Choreographer 渲染框架等底层原理。
📋 章节目录
| 节 | 主题 |
|---|---|
| 11.1 | Kotlin 协程原理(CPS / Continuation 状态机) |
| 11.2 | Flow 冷热流原理 |
| 11.3 | 委托属性(Delegate Property) |
| 11.4 | Kotlin DSL 与内联函数 |
| 11.5 | Android Binder 通信机制 |
| 11.6 | Handler / Looper / MessageQueue |
| 11.7 | Choreographer 与 VSYNC 渲染 |
| 11.8 | Jetpack Compose 重组原理 |
11.1 Kotlin 协程原理
CPS 变换与 Continuation 状态机
Kotlin 编译器将 suspend 函数通过 CPS(Continuation-Passing Style) 变换为状态机:
kotlin
// 原始 suspend 函数
suspend fun fetchUserAndOrder(userId: Int): Pair<User, Order> {
val user = fetchUser(userId) // 挂起点 1
val order = fetchOrder(user.orderId) // 挂起点 2
return user to order
}
// 编译器将其转换为(伪代码):
class FetchUserAndOrderStateMachine(
private val completion: Continuation<Pair<User, Order>>
) : Continuation<Any?> {
var state = 0 // 当前执行到哪个挂起点
var user: User? = null
override val context = completion.context
override fun resumeWith(result: Result<Any?>) {
when (state) {
0 -> {
// 第一次调用:执行 fetchUser,挂起
state = 1
val future = fetchUser(userId, this) // 传入 this 作为回调
if (future == COROUTINE_SUSPENDED) return // 真正挂起
// 如果没有挂起(同步完成),继续往下
user = future as User
resumeWith(Result.success(user))
}
1 -> {
// fetchUser 完成后恢复:执行 fetchOrder
user = result.getOrThrow() as User
state = 2
val future = fetchOrder(user!!.orderId, this)
if (future == COROUTINE_SUSPENDED) return
resumeWith(result)
}
2 -> {
// fetchOrder 完成后恢复:返回结果
val order = result.getOrThrow() as Order
completion.resumeWith(Result.success(user!! to order))
}
}
}
}
CoroutineScope 与结构化并发
kotlin
// 结构化并发:子协程的生命周期与父协程绑定
fun structuredConcurrencyDemo() {
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Main)
scope.launch {
// 父协程
val child1 = async { fetchUser(1) }
val child2 = async { fetchOrder(1) }
// 一个子协程失败不影响其他(SupervisorJob)
try {
val user = child1.await()
val order = child2.await()
} catch (e: Exception) {
// 处理失败
}
// scope 取消时,child1 和 child2 都会被取消
}
// 取消整个 scope(包含所有子协程)
scope.cancel()
}
// 协程上下文(CoroutineContext)
fun contextDemo() {
val context = Dispatchers.IO + // 线程池
CoroutineName("MyCoroutine") + // 命名(调试用)
SupervisorJob() + // Job:控制生命周期
CoroutineExceptionHandler { _, e -> // 异常处理
Log.e("Coroutine", "Unhandled exception", e)
}
CoroutineScope(context).launch {
// 在 IO 线程池执行,带有协程名和异常处理
}
}
// withContext:在不同线程切换
suspend fun multiThreadExample(): String {
val data = withContext(Dispatchers.IO) {
// IO 线程:执行网络请求、文件读写
fetchDataFromNetwork()
}
// 回到调用方的 Context(如 Main 线程)
return processData(data)
}
private suspend fun fetchDataFromNetwork(): String = "data"
private fun processData(data: String): String = data
协程取消机制(Cooperative Cancellation)
kotlin
// 协程取消是协作式的(非强制终止)
suspend fun cancellableWork() {
repeat(1000) { i ->
// ✅ 定期检查取消状态
if (!isActive) return // 提前返回
// 或者:
ensureActive() // 如果已取消,抛出 CancellationException
// ✅ 挂起点(suspend)会自动检查取消
delay(100) // 挂起时如果已取消,自动抛出异常
doWork(i)
}
}
// ❌ 无挂起点的密集计算无法自动取消
suspend fun nonCancellableBad() = withContext(Dispatchers.Default) {
var result = 0L
for (i in 0..Long.MAX_VALUE) {
result += i // 没有 isActive 检查,无法取消!
}
result
}
// ✅ 密集计算加入取消检查
suspend fun cancellableComputation() = withContext(Dispatchers.Default) {
var result = 0L
for (i in 0..1_000_000L) {
ensureActive() // 每次循环检查取消状态
result += i
}
result
}
// withContext(NonCancellable):不可取消区域(如资源释放)
suspend fun withNonCancellable() {
try {
// 可取消的工作
} finally {
withContext(NonCancellable) {
// 即使协程被取消,此处也会执行(用于清理资源)
closeConnection()
}
}
}
private fun closeConnection() {}
private fun doWork(i: Int) {}
11.2 Flow 冷热流原理
冷流(Cold Flow)vs 热流(Hot Flow)
冷流(Flow):
- 创建时不产生数据
- 每个 collect 触发一个独立的流
- 典型:flow { } builder、Room DAO 返回的 Flow
热流(SharedFlow / StateFlow):
- 独立于 collector 产生数据
- 多个 collector 共享同一流
- 典型:MutableStateFlow、MutableSharedFlow、广播
kotlin
// 冷流原理:每次 collect 执行 producer block
fun coldFlowExample() {
val coldFlow = flow {
println("开始生产数据") // 每次 collect 都会打印
emit(1)
emit(2)
emit(3)
}
// 两个 collector,产生两个独立的流
runBlocking {
coldFlow.collect { println("Collector1: $it") }
coldFlow.collect { println("Collector2: $it") }
}
// 输出:
// 开始生产数据
// Collector1: 1, 2, 3
// 开始生产数据
// Collector2: 1, 2, 3
}
// Flow 操作符原理(每个操作符都是一个新的 Flow)
val transformedFlow = flow { emit(1); emit(2); emit(3) }
.map { it * 2 } // 返回新 Flow
.filter { it > 2 } // 返回新 Flow
.onEach { /* side effect */ } // 返回新 Flow
// 最终:链式 Flow,collect 时从上游传递
// StateFlow 实现原理
class CustomStateFlow<T>(initialValue: T) {
private var _value = initialValue
private val collectors = mutableListOf<FlowCollector<T>>()
// 更新时通知所有 collector
suspend fun setValue(newValue: T) {
if (_value != newValue) { // 去重:相同值不通知
_value = newValue
collectors.forEach { it.emit(newValue) }
}
}
}
// SharedFlow vs StateFlow
// StateFlow:永远有值(初始值),Collector 立即收到当前值,去重,replay=1
// SharedFlow:可配置 replay(多久的历史值),不去重,无初始值
val stateFlow = MutableStateFlow(0) // 有初始值,replay=1,去重
val sharedFlow = MutableSharedFlow<Int>( // 可配置
replay = 0, // 不缓存历史
extraBufferCapacity = 64,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
// 将冷流转为热流(shareIn / stateIn)
class NetworkRepository(
private val api: Api,
private val scope: CoroutineScope
) {
// 将冷流转为热 StateFlow(多个订阅者共享同一网络请求)
val networkStatus: StateFlow<NetworkStatus> = flow {
// 定期刷新网络状态
while (true) {
emit(api.checkStatus())
delay(30_000)
}
}.stateIn(
scope = scope,
started = SharingStarted.WhileSubscribed(5_000), // 无订阅者 5s 后停止
initialValue = NetworkStatus.Unknown
)
}
Flow 错误处理与背压
kotlin
// catch:捕获上游异常
fun errorHandlingFlow() {
flow {
emit(1)
throw IOException("网络错误")
emit(2) // 不会执行
}
.catch { e ->
emit(-1) // 发送降级值
// 或者 throw e 重新抛出
}
.onCompletion { cause ->
// 无论正常/异常结束都会调用
println("流结束,原因:$cause")
}
}
// buffer:生产者不等消费者(背压处理)
fun backpressureHandling() {
flow {
repeat(100) { i ->
emit(i) // 快速生产
}
}
.buffer(capacity = 64) // 缓冲区
.conflate() // 只保留最新值(丢中间值)
.collectLatest { value ->
// 如果新值来了,取消当前处理,处理最新值
delay(100) // 慢速消费
processValue(value)
}
}
private fun processValue(value: Int) {}
11.3 委托属性(Delegate Property)
kotlin
// 委托属性原理:operator getValue / setValue
class LazyDelegate<T>(private val initializer: () -> T) {
private var value: T? = null
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value ?: initializer().also { value = it }
}
}
// 自定义 by lazy 等效实现
val expensiveValue: String by LazyDelegate { computeExpensiveValue() }
// 标准委托
val lazyValue: String by lazy { "只计算一次" }
var observableValue: String by Delegates.observable("初始值") { prop, old, new ->
println("${prop.name}: $old → $new")
}
var vetoableValue: Int by Delegates.vetoable(0) { _, _, new ->
new >= 0 // 只允许非负数
}
// Map 委托(从 Map 读取属性)
class UserConfig(map: Map<String, Any?>) {
val name: String by map
val age: Int by map
val email: String by map
}
val config = UserConfig(mapOf("name" to "张三", "age" to 25, "email" to "zhang@example.com"))
println(config.name) // "张三"
// ViewModel 中的 by viewModels()
class MyFragment : Fragment() {
private val viewModel: MyViewModel by viewModels() // 委托工厂创建 ViewModel
private val sharedViewModel: SharedViewModel by activityViewModels()
}
// Compose 中的 by remember / by state
@Composable
fun ComposeDelegatesDemo() {
var count by remember { mutableStateOf(0) } // 委托 MutableState
val isEven by remember(count) { derivedStateOf { count % 2 == 0 } }
Column {
Text("计数:$count,${if (isEven) "偶数" else "奇数"}")
Button(onClick = { count++ }) { Text("增加") }
}
}
private fun computeExpensiveValue(): String = "expensive"
11.4 Kotlin DSL 与内联函数
构建类型安全 DSL
kotlin
// HTML DSL 示例
@DslMarker
annotation class HtmlDsl
@HtmlDsl
class TagBuilder(private val tagName: String) {
private val children = mutableListOf<String>()
private val attributes = mutableMapOf<String, String>()
fun attr(name: String, value: String) { attributes[name] = value }
fun tag(name: String, block: TagBuilder.() -> Unit) {
val child = TagBuilder(name).also(block).build()
children.add(child)
}
fun text(content: String) { children.add(content) }
fun build(): String {
val attrs = attributes.entries.joinToString(" ") { "${it.key}=\"${it.value}\"" }
val attrsStr = if (attrs.isNotBlank()) " $attrs" else ""
return "<$tagName$attrsStr>${children.joinToString("")}</$tagName>"
}
}
fun html(block: TagBuilder.() -> Unit): String = TagBuilder("html").also(block).build()
// 使用
val page = html {
tag("head") {
tag("title") { text("Android 文档") }
}
tag("body") {
attr("class", "main")
tag("h1") { text("Hello Android!") }
}
}
// Compose-like DSL(构建者模式)
@DslMarker annotation class RequestDsl
@RequestDsl
class NetworkRequest private constructor() {
var url: String = ""
var method: String = "GET"
var timeout: Long = 30_000L
private val headers = mutableMapOf<String, String>()
private var body: String? = null
fun headers(block: MutableMap<String, String>.() -> Unit) = headers.block()
fun body(content: String) { body = content }
fun build(): OkHttp3Request = OkHttp3Request(url, method, headers, body, timeout)
companion object {
fun create(block: NetworkRequest.() -> Unit): OkHttp3Request {
return NetworkRequest().also(block).build()
}
}
}
// 使用 DSL
val request = NetworkRequest.create {
url = "https://api.example.com/products"
method = "POST"
timeout = 60_000L
headers {
put("Authorization", "Bearer token")
put("Content-Type", "application/json")
}
body("""{"page": 1, "limit": 20}""")
}
data class OkHttp3Request(val url: String, val method: String, val headers: Map<String, String>, val body: String?, val timeout: Long)
内联函数(inline)
kotlin
// inline 消除 lambda 的对象创建开销
inline fun <T> measureTime(block: () -> T): Pair<T, Long> {
val start = System.currentTimeMillis()
val result = block() // 内联展开,不创建 Function 对象
return result to System.currentTimeMillis() - start
}
// crossinline:lambda 中不能 return(跨边界)
inline fun runWithCallback(crossinline block: () -> Unit) {
Thread { block() }.start() // block 跨越了 lambda 边界
}
// noinline:特定参数不内联
inline fun processItems(
items: List<Int>,
transform: (Int) -> String, // 内联
noinline filter: (String) -> Boolean // 不内联(需要作为对象传递)
): List<String> {
val filtered: List<String> = items.map(transform).filter(filter)
return filtered
}
// reified:在内联函数中获取类型信息(必须配合 inline)
inline fun <reified T> parseJson(json: String): T {
return Gson().fromJson(json, T::class.java) // T::class 在内联后可用
}
// 使用
val user: User = parseJson<User>("""{"name": "张三"}""")
val users: List<User> = parseJson<List<User>>("""[{"name": "张三"}]""")
11.5 Android Binder 通信机制
Binder 是 Android 的核心 IPC(进程间通信)机制:
用户进程A(Client) 内核(Binder Driver) 用户进程B(Server,如系统服务)
│ │ │
│ 1. 调用 transact() │ │
├──────────────────────→ │ │
│ │ 2. 内核复制数据 │
│ ├──────────────────────→ │
│ │ 3. onTransact() 回调 │
│ │ │ 执行服务逻辑
│ │ 4. 返回结果 │
│ 5. 返回结果 ← ─────────────────────── │
←────────────────────── │ │
优点:
① 只需一次数据拷贝(Binder 将数据映射到接收方地址空间)
(相比 Socket 需要两次拷贝:发送方→内核,内核→接收方)
② 安全:每次 Binder 调用附带调用方 PID/UID,无法伪造
③ 面向对象:Binder 对象像远程方法调用
kotlin
// 定义 AIDL 接口
// IProductService.aidl
interface IProductService {
List<Product> getProducts();
Product getProductById(int id);
void updateFavorite(int id, boolean isFavorite);
}
// Server 端(Service 中实现)
class ProductRemoteService : Service() {
private val binder = object : IProductService.Stub() {
override fun getProducts(): List<Product> {
// 在服务进程中运行(Binder 线程池)
return database.productDao().getAllProductsSync()
}
override fun getProductById(id: Int): Product {
return database.productDao().getProductByIdSync(id)!!.toDomain()
}
override fun updateFavorite(id: Int, isFavorite: Boolean) {
database.productDao().updateFavoriteStatusSync(id, isFavorite)
}
}
override fun onBind(intent: Intent): IBinder = binder
}
// Client 端(绑定服务)
class ProductActivity : AppCompatActivity() {
private var productService: IProductService? = null
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
productService = IProductService.Stub.asInterface(service)
// 可以调用远程方法(注意:不能在主线程调用耗时方法!)
}
override fun onServiceDisconnected(name: ComponentName) {
productService = null
}
}
override fun onStart() {
super.onStart()
bindService(
Intent(this, ProductRemoteService::class.java),
serviceConnection,
Context.BIND_AUTO_CREATE
)
}
override fun onStop() {
super.onStop()
unbindService(serviceConnection)
}
}
11.6 Handler / Looper / MessageQueue
kotlin
// 核心原理
/*
Looper:
- 每个线程可以有一个 Looper
- 维护一个 MessageQueue(优先级队列)
- 不断从 MessageQueue 中取出 Message 分发给 Handler
Handler:
- 绑定到创建它的线程的 Looper
- sendMessage() → 将 Message 放入 MessageQueue
- handleMessage() → 在其 Looper 所在线程执行
主线程(Main/UI Thread)启动时自动创建 Looper
*/
// 手动创建 Looper 线程
class WorkThread : Thread("worker") {
private var handler: Handler? = null
private var looper: Looper? = null
@Volatile private var running = true
override fun run() {
Looper.prepare() // 创建 MessageQueue
looper = Looper.myLooper()
synchronized(this) {
handler = Handler(looper!!) { msg ->
when (msg.what) {
MSG_TASK -> processTask(msg.obj as Runnable)
}
true
}
notifyAll() // 通知 handler 已创建
}
Looper.loop() // 开始轮询(阻塞)
}
fun post(task: Runnable) {
handler?.sendMessage(Message.obtain(handler, MSG_TASK, task))
}
fun quit() {
looper?.quitSafely() // 处理完当前 Message 后退出
}
private fun processTask(task: Runnable) { task.run() }
companion object { const val MSG_TASK = 1 }
}
// Message 对象池(复用,减少内存分配)
val msg = Message.obtain() // 从对象池获取
msg.what = 1
msg.obj = data
handler.sendMessage(msg)
// 分发后自动回收到对象池
// 延迟消息
handler.postDelayed({ updateUI() }, 1000L)
handler.sendMessageDelayed(Message.obtain(handler, MSG_UPDATE), 500L)
// 取消延迟消息
handler.removeCallbacks(updateRunnable)
handler.removeMessages(MSG_UPDATE)
// 查看 MessageQueue 中的 Message
// 只有 Debug 时才用(反射)
11.7 Choreographer 与 VSYNC 渲染
VSYNC(垂直同步)信号:显示器每 16.67ms 发出一次信号,驱动一帧的渲染
VSYNC
│
Choreographer.FrameCallback
│
├── Input(触摸事件处理)
│
├── Animation(属性动画更新)
│
└── Traversal(View 树遍历:measure → layout → draw)
│
└── 生成 DisplayList(Record Canvas)
│
└── → RenderThread → GPU → 屏幕
kotlin
// Choreographer 使用
val choreographer = Choreographer.getInstance()
// 注册下一帧回调(单次)
choreographer.postFrameCallback { frameTimeNanos ->
val frameTimeMs = frameTimeNanos / 1_000_000
performAnimation(frameTimeMs)
// 如果需要持续动画,再次注册
choreographer.postFrameCallback(this)
}
// View 的 invalidate() 机制
/*
view.invalidate()
→ ViewRootImpl.scheduleTraversals()
→ Choreographer.postCallback(CALLBACK_TRAVERSAL, traversal)
→ 等待下一个 VSYNC 信号
→ 执行 ViewRootImpl.performTraversals()
→ measure() → layout() → draw()
*/
// 监控帧率(FrameMetrics API)
@RequiresApi(Build.VERSION_CODES.O)
fun monitorFrameMetrics(window: Window) {
window.addOnFrameMetricsAvailableListener({ _, frameMetrics, _ ->
val totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION) / 1_000_000
if (totalDuration > 16) {
Log.w("FrameMetrics", "Frame took ${totalDuration}ms(Jank!)")
}
}, Handler(Looper.getMainLooper()))
}
11.8 Jetpack Compose 重组原理
kotlin
/*
Compose 快照系统(Snapshot System):
State(MutableState)存储在 Snapshot 中
当 State 被读取时,当前 Scope 被记录为依赖(ReadObserver)
当 State 被修改时,所有依赖的 Scope 被标记为需要重组
Choreographer 下一帧时,执行所有标记的重组
*/
// 理解 @Composable 函数的调用机制
@Composable
fun Counter() {
var count by remember { mutableStateOf(0) }
// Compose Runtime 将此函数包装为 Composable Node
// 分配一个 "Slot Table" 的内存位置存储 count
// 当 count 变化时,只重组读取了 count 的部分
Column {
Text("Count: $count") // 订阅 count,count 变化时此处重组
Button(onClick = { count++ }) {
Text("点击") // 不读 count,不重组
}
}
}
// 副作用 API 的实现原理
@Composable
fun SideEffectDemo() {
// LaunchedEffect:只在 key 变化时重新执行
// 实现:比较 key 与上一次,如果不同,取消旧协程,启动新协程
LaunchedEffect(Unit) {
// 只在首次组合时执行
}
// DisposableEffect:在取消组合时执行清理
// 实现:在 Composition 的生命周期钩子中注册清理函数
DisposableEffect(Unit) {
val observer = MyObserver()
// 注册
onDispose {
// 解注册(组件离开时)
}
}
// rememberUpdatedState:捕获最新值而不触发重组
// 用途:在长时间回调(如定时器)中使用最新的状态
val count by remember { mutableStateOf(0) }
val currentCount by rememberUpdatedState(count)
LaunchedEffect(Unit) {
delay(5000)
println(currentCount) // 5秒后使用最新的 count(而非 LaunchedEffect 启动时的值)
}
}
// 稳定性系统(Stability System)
/*
Compose 编译器分析 @Composable 函数的参数:
- Stable(稳定):参数不变时,跳过重组(Smart Recomposition)
- 基本类型(Int, String, Boolean...)
- @Immutable class
- @Stable 标注的类
- 所有 fields 为 stable 的 data class
- Unstable(不稳定):参数变化时,总是重组
- List, Map, Set(接口,不稳定)→ 改用 kotlinx.collections.immutable
- 含 var fields 的类
*/
// ✅ 使用不可变集合
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.8")
@Composable
fun StableList(items: ImmutableList<String>) {
// items 是稳定类型,列表不变时不重组
LazyColumn {
items(items) { item -> Text(item) }
}
}
Demo 代码:chapter11
kotlin
// chapter11/PrinciplesDemo.kt
package com.example.androiddemos.chapter11
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
@Composable
fun Chapter11PrinciplesDemo() {
var selectedDemo by remember { mutableStateOf(0) }
val demos = listOf("协程原理", "Flow 冷热流", "委托属性", "重组分析")
Column(modifier = Modifier.fillMaxSize().padding(16.dp)) {
Text("Kotlin & Android 原理", style = MaterialTheme.typography.headlineSmall)
Spacer(Modifier.height(8.dp))
SingleChoiceSegmentedButtonRow(modifier = Modifier.fillMaxWidth()) {
demos.forEachIndexed { index, label ->
SegmentedButton(
selected = selectedDemo == index,
onClick = { selectedDemo = index },
shape = SegmentedButtonDefaults.itemShape(index, demos.size)
) { Text(label, style = MaterialTheme.typography.labelSmall) }
}
}
Spacer(Modifier.height(16.dp))
when (selectedDemo) {
0 -> CoroutinePrinciplesContent()
1 -> FlowPrinciplesContent()
2 -> DelegatePrinciplesContent()
3 -> RecompositionAnalysisContent()
}
}
}
@Composable
private fun CoroutinePrinciplesContent() {
var coroutineResult by remember { mutableStateOf("点击运行协程示例") }
val scope = rememberCoroutineScope()
LazyColumn(verticalArrangement = Arrangement.spacedBy(8.dp)) {
item {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text("协程 CPS 变换原理", style = MaterialTheme.typography.titleSmall)
Spacer(Modifier.height(4.dp))
Text(
"suspend 函数被编译为状态机\n" +
"• state=0:执行第一个挂起点前\n" +
"• state=1:第一个挂起点后\n" +
"• 每次恢复从 resumeWith() 进入",
style = MaterialTheme.typography.bodySmall
)
}
}
}
item {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text("结构化并发示例", style = MaterialTheme.typography.titleSmall)
Spacer(Modifier.height(8.dp))
Text(coroutineResult)
Spacer(Modifier.height(8.dp))
Button(onClick = {
scope.launch {
coroutineResult = "执行中..."
val a = async { delay(300); "任务A" }
val b = async { delay(500); "任务B" }
coroutineResult = "${a.await()} + ${b.await()} 完成(并行执行)"
}
}) { Text("并行执行 async") }
}
}
}
}
}
@Composable
private fun FlowPrinciplesContent() {
var flowLog by remember { mutableStateOf("点击观察 Flow 行为") }
val scope = rememberCoroutineScope()
val hotFlow = remember { MutableSharedFlow<Int>(replay = 0) }
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text("Flow 冷流 vs 热流", style = MaterialTheme.typography.titleSmall)
Text("• 冷流:每次 collect 触发独立流\n• 热流:多个 collector 共享数据", style = MaterialTheme.typography.bodySmall)
Spacer(Modifier.height(8.dp))
Text(flowLog, style = MaterialTheme.typography.bodySmall)
Spacer(Modifier.height(8.dp))
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = {
scope.launch {
flowLog = ""
flow { emit(1); emit(2); emit(3) }.collect {
flowLog += "冷流: $it\n"
}
}
}) { Text("冷流") }
Button(onClick = {
scope.launch { hotFlow.emit((1..100).random()) }
}) { Text("发射热流值") }
}
}
}
}
}
@Composable
private fun DelegatePrinciplesContent() {
// 演示 by remember / by state 委托
var delegatedCount by remember { mutableStateOf(0) }
val isPositive by remember(delegatedCount) { derivedStateOf { delegatedCount >= 0 } }
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text("委托属性 Demo", style = MaterialTheme.typography.titleSmall)
Spacer(Modifier.height(8.dp))
Text("当前值: $delegatedCount(${if (isPositive) "正数" else "负数"})")
Text("by remember { mutableStateOf(0) } - 读/写委托给 MutableState", style = MaterialTheme.typography.bodySmall)
Spacer(Modifier.height(8.dp))
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
Button(onClick = { delegatedCount-- }) { Text("-1") }
Button(onClick = { delegatedCount++ }) { Text("+1") }
OutlinedButton(onClick = { delegatedCount = 0 }) { Text("归零") }
}
}
}
}
@Composable
private fun RecompositionAnalysisContent() {
var triggerCount by remember { mutableStateOf(0) }
var rootRecomposeCount by remember { mutableIntStateOf(0) }
var childRecomposeCount by remember { mutableIntStateOf(0) }
// 记录根节点重组次数
SideEffect { rootRecomposeCount++ }
Column(verticalArrangement = Arrangement.spacedBy(8.dp)) {
Card(modifier = Modifier.fillMaxWidth()) {
Column(modifier = Modifier.padding(16.dp)) {
Text("重组分析", style = MaterialTheme.typography.titleSmall)
Text("根节点重组次数: $rootRecomposeCount", style = MaterialTheme.typography.bodyMedium)
Spacer(Modifier.height(8.dp))
// 子组件 - 读取 triggerCount
StableChildComponent(
count = triggerCount,
onRecompose = { childRecomposeCount++ }
)
Text("子节点重组次数: $childRecomposeCount", style = MaterialTheme.typography.bodySmall)
Spacer(Modifier.height(8.dp))
Button(onClick = { triggerCount++ }) {
Text("触发状态变化(第 $triggerCount 次)")
}
}
}
}
}
@Composable
private fun StableChildComponent(count: Int, onRecompose: () -> Unit) {
SideEffect { onRecompose() } // 每次重组调用
Text("子组件读取: $count", style = MaterialTheme.typography.bodySmall)
}
章节总结
| 知识点 | 必掌握程度 | 面试频率 |
|---|---|---|
| 协程 CPS 变换 / 状态机 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 协程取消协作机制 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 结构化并发 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Cold Flow vs Hot Flow | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| StateFlow vs SharedFlow | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| stateIn / shareIn | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| 委托属性原理 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| Kotlin inline / reified | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Binder 一次拷贝原理 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Handler / Looper / MessageQueue | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Choreographer / VSYNC | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Compose Snapshot 系统 | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |