Android Clean Architecture 架構指南

隨著 App 規模變大,如果把所有程式碼都寫在 Activity 或 Composable 中,很快就會變成一團難以維護的義大利麵 (Spaghetti Code)。

Google 官方推薦的現代 Android 架構 (Guide to App Architecture) 基於 Clean ArchitectureMVVM (Model-View-ViewModel) 模式,將應用程式分為三層。

UI 層 (Presentation Layer)

這一層負責顯示資料處理使用者互動

  • Views / Composables:負責渲染畫面。
  • ViewModel:負責持有 UI 狀態 (UI State) 並處理業務邏輯。它不應該持有任何 Android Framework 的引用 (如 Context),以利於單元測試。

資料流向

  • ViewModel 暴露 StateFlow 給 UI 觀察。
  • UI 觸發 Event 呼叫 ViewModel 的函式。

Domain 層 (可選)

這一層封裝了複雜的業務邏輯。它由 Use Cases (Interactors) 組成。

例如:GetFormattedDateUseCase, CalculateTotalCartPriceUseCase

  • 它不依賴 UI 層。
  • 它不依賴 Android Framework。
  • 它只依賴 Data 層。

這層是純粹的 Kotlin/Java 程式碼,最容易測試。對於簡單的專案,這層可以省略,邏輯直接寫在 ViewModel。

Data 層

這一層負責提供資料。它隱藏了資料來源的細節 (是來自網路、資料庫、還是快取?)。

  • Repository:對外暴露資料介面。它是 Single Source of Truth。它負責協調不同的 Data Source。
  • Data Source:實際存取資料的物件。
    • RemoteDataSource (Retrofit, API)
    • LocalDataSource (Room, DataStore)

架構範例

假設我們要開發一個「顯示新聞列表」的功能:

  1. NewsScreen (UI):監聽 NewsViewModel.uiState,顯示列表。點擊新聞時呼叫 viewModel.openNews(id)
  2. NewsViewModel (Presentation):呼叫 Repository 取得新聞,將結果轉換為 UiState.Success(newsList)
  3. NewsRepository (Data):檢查有沒有快取?
    • 有:從 NewsDao (Room) 讀取。
    • 無:從 NewsApiService (Retrofit) 下載,存入 Room,再回傳。

為什麼要這樣設計?

  1. 關注點分離 (Separation of Concerns):UI 只管顯示,Data 只管資料,各司其職。
  2. 可測試性:每一層都可以獨立進行單元測試 (Unit Test)。
  3. 可維護性:更換資料來源(例如從 SQLite 換成 Realm)只需要修改 Data 層,UI 層完全不需要動。

在接下來的章節,我們將深入探討 ViewModel, Lifecycle依賴注入 (DI) 如何支撐這個架構。