各位戰士,歡迎來到第二十一天的戰場。在過去的一週,我們投身於慘烈的 UI 流暢度陣地戰。我們學會了用 ConstraintLayout
攻克佈局的堡壘,用 ListAdapter
精準打擊 RecyclerView
的敵人,還學會了在 Jetpack Compose 的新戰場上打贏 Recomposition 戰爭。
所有這些戰術,無論多麼精妙,都服務於一個最終的戰略目標。今天,我們就要頒布這條統率整個流暢度戰爭的最高軍法,一條無論在傳統 View 體系還是 Jetpack Compose 中都神聖不可侵犯的鐵律:
任何時候,任何情況下,都絕不允許阻塞主執行緒 (Main Thread / UI Thread)!
回顧我們奮戰至今的一切,Jank 的根源無一例外都是主執行緒被佔用太久,導致它錯過了 16ms 一次的 VSYNC 軍令。今天,我們就要把那些最常導致阻塞的「頭號通緝犯」揪出來,並學習如何用我們最強的「特種部隊」——Kotlin 協程——來制服它們。
以下是在主執行緒上執行時,會立刻引發性能災難的「慣犯」。請務必將它們刻入你的 DNA。
NetworkOnMainThreadException
讓你的 App 崩潰,這是一種強制性的保護措施。SharedPreferences
、讀寫手機內部或外部儲存的任何檔案。既然主執行緒如此寶貴,我們該如何處理這些耗時的「髒活累活」?答案就是:將它們交給背景執行緒。
在 Android 開發中,處理非同步任務的工具有很多(傳統 Thread、RxJava 等),但目前官方最推薦、也是最現代化的武器,就是 Kotlin 協程。
為何協程是最佳選擇?
CoroutineScope
綁定(例如 viewModelScope
)。當 ViewModel 被銷毀時,viewModelScope
會被取消,所有在這個範圍內啟動的協程也會被自動取消。這從根本上解決了非同步任務中常見的記憶體洩漏問題。async/await
和 suspend
關鍵字,可以讓我們用近乎同步的語法寫出清晰易讀的非同步程式碼,徹底告別「回呼地獄 (Callback Hell)」。讓我們看一個在 ViewModel
中載入資料的標準作戰流程:
錯誤示範 (阻塞主執行緒):
// 在 ViewModel 中
fun loadDataFromDatabase() {
// 致命錯誤!直接在主執行緒上查詢資料庫
val data = database.userDao().getAll()
_uiState.value = data
}
// 在 ViewModel 中
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
fun loadDataFromDatabase() {
// 1. 在 viewModelScope 中啟動一個協程,它會跟隨 ViewModel 的生命週期
viewModelScope.launch {
// 2. 使用 withContext 切換到 IO 執行緒池,專門處理磁碟/網路操作
val data = withContext(Dispatchers.IO) {
// 在這裡執行耗時的資料庫查詢,不會阻塞主執行緒
database.userDao().getAll()
}
// 3. withContext 結束後,自動切回主執行緒來更新 UI
_uiState.value = data
}
}
這個範式必須成為你的肌肉記憶:在 viewModelScope
中啟動協程,用 withContext
將耗時任務切到背景執行緒 (Dispatchers.IO
或 Dispatchers.Default
),然後在主執行緒更新 UI。
今天,我們為 UI 流暢度攻防戰畫下了句點,並確立了其最高指導原則:守護主執行緒。
我們學會了識別那些會阻塞主執行緒的頭號通緝犯:網路、磁碟 I/O 和大量計算。
我們掌握了使用 Kotlin 協程 這支王牌部隊,將所有耗時任務安全地移出主執行緒的標準作戰流程。
回顧這一週,我們打的是一場組合拳:一方面,透過佈局優化、RecyclerView
技巧、管理 Compose 重組,來讓我們在主執行緒上必須做的 UI 工作變得更快;另一方面,透過協程,來將所有可以在主執行緒之外做的非 UI 工作全部移走。只有兩者兼顧,才能取得 UI 流暢度的最終勝利。
陣地戰已經結束。接下來,戰爭將進入更宏觀的 【持久戰 —— 資源管理與自動化監控】。我們將把目光從使用者眼前的卡頓,轉向那些隱藏在應用背後的敵人:記憶體洩漏、過大的 APK 體積、以及如何建立自動化的哨兵來防止性能再次劣化。
我們明天見!