Skip to content

Main 与 Main.immediate

选择正确的 UI 调度器,是保证 Android 60fps (16ms/帧) 流畅度的关键细节。

致命差异:Queue vs Direct

  • Dispatchers.Main (标准):

    • 总是使用 Handler.post() 将任务扔进消息队列末尾。
    • 后果: 哪怕你已经在主线程,它也会强行排队,等待下一次 Looper 轮询。这至少会延迟一帧的执行,甚至引发掉帧。
  • Dispatchers.Main.immediate (推荐):

    • 智能判断: 先检查 Thread.currentThread() 是否是主线程。
    • : 直接执行 (Function Call),零延迟。
    • : 退化为 Handler.post()

实战:Why it matters?

场景:RecyclerView 绑定数据

kotlin
// 假设我们在 ViewModel 中加载数据
val data = repository.load()

// 切换回主线程赋值
withContext(Dispatchers.Main) { 
    // 这里会通过 Handler 发送消息
    // 如果消息队列繁忙(例如正在处理复杂的 Touch 事件),
    // UI 数据刷新会被延迟,用户会感到明显的“点击后迟钝”。
    adapter.submitList(data) 
}

withContext(Dispatchers.Main.immediate) {
    // 立即赋值!UI 瞬间响应。
    adapter.submitList(data)
}

场景:动画回调

onAnimationUpdate 等高频回调中,由于已经处在主线程,使用 Main.immediate 能够确保每一帧的计算都能在 VSYNC 信号到来前完成,避免画面撕裂或卡顿。

最佳实践总结

铁律

除非你有明确理由(比如故意想把任务推迟到下一个 Message Loop),否则所有涉及 UI 操作的场景请无脑使用 Dispatchers.Main.immediate

Jetpack 的 lifecycleScopeviewModelScope 默认使用的就是 Main.immediate