Android Jetpack Compose + MVVM 開發流程深度分析

核心組件關系圖
[View] -- 觀察 --> [ViewModel] -- 操作 --> [Repository]|                              |
Compose UI                    StateFlow/LiveData|                              |
用戶交互事件                       Room/Retrofit|                              |
[ViewModel] <-- 數據更新 -- [Data Sources]
開發流程詳解
  1. 數據層 (Model)

    • 實體類定義:Room 實體或數據類
    • Repository 模式:
      • 統一管理數據源(Room/Retrofit/文件)
      • 提供干凈的 API 給 ViewModel
  2. ViewModel 層

    • 使用 androidx.lifecycle 組件
    • 核心職責:
      • 持有 UI 狀態(StateFlow/MutableStateFlow
      • 處理業務邏輯
      • 暴露不可變狀態給 UI 層
    • 使用協程管理異步操作
  3. UI 層 (Compose)

    • 基于狀態的聲明式編程
    • 關鍵組件:
      • @Composable 函數構建 UI
      • remember 管理組件狀態
      • ViewModel 通過 viewModel() 獲取
    • 狀態管理:
      • 通過 collectAsState() 觀察 ViewModel 狀態
      • 用戶事件通過 ViewModel 方法回調
  4. 數據綁定

    • 單向數據流:
      用戶操作
      調用 ViewModel 方法
      更新 Model 層
      ViewModel 更新 State
      Compose 自動重組
  5. 依賴管理

    • 使用 Hilt 實現依賴注入:
      • @HiltViewModel 注解 ViewModel
      • @Inject 構造函數注入 Repository

Todo 應用最佳實踐實現

1. 添加依賴 (app/build.gradle)
dependencies {// Composeimplementation 'androidx.activity:activity-compose:1.8.0'implementation "androidx.compose.material3:material3:1.1.2"implementation "androidx.compose.ui:ui-tooling-preview:1.5.4"debugImplementation "androidx.compose.ui:ui-tooling:1.5.4"// Lifecycleimplementation "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2"implementation "androidx.lifecycle:lifecycle-runtime-compose:2.6.2"// Roomimplementation "androidx.room:room-runtime:2.6.0"implementation "androidx.room:room-ktx:2.6.0"kapt "androidx.room:room-compiler:2.6.0"// Hiltimplementation "com.google.dagger:hilt-android:2.48"kapt "com.google.dagger:hilt-compiler:2.48"
}
2. 數據模型
@Entity(tableName = "todos")
data class Todo(@PrimaryKey(autoGenerate = true) val id: Long = 0,val title: String,val description: String = "",val isCompleted: Boolean = false,val createdAt: LocalDateTime = LocalDateTime.now()
)
3. Repository 實現
interface TodoRepository {fun getAllTodos(): Flow<List<Todo>>suspend fun addTodo(todo: Todo)suspend fun updateTodo(todo: Todo)suspend fun deleteTodo(todo: Todo)
}class TodoRepositoryImpl @Inject constructor(private val todoDao: TodoDao
) : TodoRepository {override fun getAllTodos(): Flow<List<Todo>> = todoDao.getAll().map { list -> list.sortedByDescending { it.createdAt } }override suspend fun addTodo(todo: Todo) = todoDao.insert(todo)override suspend fun updateTodo(todo: Todo) = todoDao.update(todo)override suspend fun deleteTodo(todo: Todo) = todoDao.delete(todo)
}
4. ViewModel 實現
@HiltViewModel
class TodoViewModel @Inject constructor(private val repository: TodoRepository
) : ViewModel() {// UI 狀態封裝data class TodoUiState(val todos: List<Todo> = emptyList(),val isLoading: Boolean = false,val error: String? = null)// 使用 MutableStateFlow 管理狀態private val _uiState = MutableStateFlow(TodoUiState(isLoading = true))val uiState: StateFlow<TodoUiState> = _uiState.asStateFlow()init {loadTodos()}private fun loadTodos() {viewModelScope.launch {repository.getAllTodos().catch { e -> _uiState.value = TodoUiState(error = e.message)}.collect { todos ->_uiState.value = TodoUiState(todos = todos)}}}fun addTodo(title: String, description: String = "") {viewModelScope.launch {val newTodo = Todo(title = title, description = description)repository.addTodo(newTodo)}}fun toggleTodoCompletion(todo: Todo) {viewModelScope.launch {repository.updateTodo(todo.copy(isCompleted = !todo.isCompleted))}}fun deleteTodo(todo: Todo) {viewModelScope.launch {repository.deleteTodo(todo)}}
}
5. Compose UI 實現
@Composable
fun TodoScreen(viewModel: TodoViewModel = viewModel()
) {val uiState by viewModel.uiState.collectAsState()var showDialog by remember { mutableStateOf(false) }var newTodoTitle by remember { mutableStateOf("") }Scaffold(topBar = { TopAppBar(title = { Text("Todo List") }) },floatingActionButton = {FloatingActionButton(onClick = { showDialog = true }) {Icon(Icons.Filled.Add, "Add Todo")}}) { padding ->when {uiState.isLoading -> Center { CircularProgressIndicator() }uiState.error != null -> Center { Text("Error: ${uiState.error}") }else -> TodoList(todos = uiState.todos,onToggleComplete = viewModel::toggleTodoCompletion,onDelete = viewModel::deleteTodo,modifier = Modifier.padding(padding))}}if (showDialog) {AlertDialog(onDismissRequest = { showDialog = false },title = { Text("Add New Todo") },text = {TextField(value = newTodoTitle,onValueChange = { newTodoTitle = it },label = { Text("Title") })},confirmButton = {Button(onClick = {viewModel.addTodo(newTodoTitle)newTodoTitle = ""showDialog = false},enabled = newTodoTitle.isNotBlank()) {Text("Add")}},dismissButton = {Button(onClick = { showDialog = false }) {Text("Cancel")}})}
}@Composable
fun TodoList(todos: List<Todo>,onToggleComplete: (Todo) -> Unit,onDelete: (Todo) -> Unit,modifier: Modifier = Modifier
) {LazyColumn(modifier = modifier) {items(items = todos,key = { it.id }) { todo ->TodoItem(todo = todo,onCheckedChange = { onToggleComplete(todo) },onDelete = { onDelete(todo) })}}
}@Composable
fun TodoItem(todo: Todo,onCheckedChange: (Boolean) -> Unit,onDelete: () -> Unit
) {Card(modifier = Modifier.fillMaxWidth().padding(8.dp),elevation = CardDefaults.cardElevation(defaultElevation = 2.dp)) {Row(modifier = Modifier.padding(16.dp),verticalAlignment = Alignment.CenterVertically) {Checkbox(checked = todo.isCompleted,onCheckedChange = onCheckedChange)Column(modifier = Modifier.weight(1f)) {Text(text = todo.title,style = MaterialTheme.typography.titleMedium,textDecoration = if (todo.isCompleted) TextDecoration.LineThrough else null)if (todo.description.isNotBlank()) {Text(text = todo.description,style = MaterialTheme.typography.bodySmall)}}IconButton(onClick = onDelete) {Icon(Icons.Filled.Delete, "Delete")}}}
}
6. 數據庫配置 (Room)
@Database(entities = [Todo::class], version = 1)
abstract class AppDatabase : RoomDatabase() {abstract fun todoDao(): TodoDao
}@Dao
interface TodoDao {@Query("SELECT * FROM todos")fun getAll(): Flow<List<Todo>>@Insertsuspend fun insert(todo: Todo)@Updatesuspend fun update(todo: Todo)@Deletesuspend fun delete(todo: Todo)
}

最佳實踐要點

  1. 狀態管理

    • 使用密封類管理 UI 狀態(Loading/Success/Error)
    • ViewModel 暴露不可變 StateFlow,Compose 通過 collectAsState() 觀察
    • UI 組件保持無狀態,通過參數接收數據
  2. 性能優化

    • 使用 remember 緩存計算結果
    • 為 LazyColumn 的 items 設置唯一 key
    • 使用 derivedStateOf 處理復雜狀態轉換
  3. 架構分層

    調用
    調用
    本地數據
    遠程數據
    UI Layer
    ViewModel
    Repository
    Room
    Retrofit
  4. 測試策略

    • ViewModel 測試:使用 TestCoroutineDispatcher
    • Compose UI 測試:使用 createComposeRule
    • Repository 測試:Mock 數據源
  5. 用戶交互優化

    • 添加 Undo 刪除功能(使用 Snackbar)
    • 實現本地搜索/過濾
    • 添加拖拽排序支持
  6. 錯誤處理

    • 在 Repository 捕獲數據源異常
    • ViewModel 將異常轉換為用戶友好消息
    • UI 層顯示錯誤狀態并提供重試選項

此實現遵循了 Android 官方架構指南,結合了 Compose 的聲明式特性和 MVVM 的響應式數據管理,提供了可測試、可維護的現代化 Android 應用架構。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/915854.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/915854.shtml
英文地址,請注明出處:http://en.pswp.cn/news/915854.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Tailwind CSS快速上手 Tailwind CSS的安裝、配置、使用

&#x1f4da;前言 在Web前端開發的歷史長河中&#xff0c;CSS的編寫方式經歷了多次演進&#xff0c;從早期的原生CSS 到 CSS預處理(Less/Sass/Stylus) 到 CSS-in-JS(Styled-Components/Emotion) 再到 Utility-First 原子化CSS。每一種演進方案其本質都是圍繞“開發效率”、“…

單例模式的智慧:從UVM看控制的藝術

有時候&#xff0c;生活中的很多東西其實只需要一個就夠了&#xff0c;就像一個公司只需要一個CEO&#xff0c;一個王朝只需要一個皇帝。在UVM驗證環境中&#xff0c;也有很多這樣的需求——有些對象&#xff0c;我們希望它在整個仿真過程中只存在一個實例。這就是我們今天要聊…

Hexo - 免費搭建個人博客01 - 安裝軟件工具

導言我的博客&#xff1a;https://q164129345.github.io/ Hexo 作為一個 Node.js 框架&#xff0c;它依賴于 Node.js 運行時環境來執行。 一、安裝Node.js官方網址&#xff1a;https://nodejs.org/zh-cn追求系統穩定性、可靠性以及希望減少維護頻率的用戶來說&#xff0c;LTS版…

【Kubernetes】集群啟動nginx,觀察端口映射,work節點使用kubectl配置

參考b站叩丁狼總結&#xff1a;完整版Kubernetes&#xff08;K8S&#xff09;全套入門微服務實戰項目&#xff0c;帶你一站式深入掌握K8S核心能力 在master節點執行 kubectl create deployment nginx --imagenginxkubectl expose deployment nginx --port80 --typeNodePort1. …

20250704-基于強化學習在云計算環境中的虛擬機資源調度研究

基于強化學習在云計算環境中的虛擬機資源調度研究 隨著云計算規模的持續擴大&#xff0c;數據中心虛擬機資源調度面臨動態負載、異構資源適配及多目標優化等挑戰。傳統啟發式算法在復雜場景下易陷入局部最優&#xff0c;而深度強化學習&#xff08;DRL&#xff09;憑借序貫決策…

day 33打卡

day 21 常見的降維算法 # 先運行之前預處理好的代碼 import pandas as pd import numpy as np import matplotlib.pyplot as plt import seaborn as sns import warnings warnings.filterwarnings(ignore)# 設置中文字體 plt.rcParams[font.sans-serif] [SimHei] plt.rcParam…

sec(x)積分推導

在MATLAB中繪制 sec?(x)、cos(x) 和 ln?∣sec?(x)tan?(x)∣的函數圖像&#xff0c;需要特別注意 sec?(x) 在 cos?(x)0&#xff08;即 xπ/2kπ&#xff09;處的奇點。&#xff08;deepseek生成代碼&#xff09;% 定義x范圍&#xff08;-2π到2π&#xff09;&#xff0c;…

gpt面試題

vue面試題 &#x1f4a1; 一、響應式系統相關 ?1. Vue 3 的響應式系統是如何實現的&#xff1f;和 Vue 2 有何本質區別&#xff1f; 答案&#xff1a; Vue 3 使用 Proxy 實現響應式&#xff08;位于 vue/reactivity 模塊&#xff09;&#xff0c;替代 Vue 2 的 Object.defineP…

【基于OpenCV的圖像處理】圖像預處理之圖像色彩空間轉換以及圖像灰度化處理

目錄 零、寫在前面的話 一、圖像色彩空間轉換 1.1 RGB顏色空間 1.1.1 RGB顏色空間概念 1.1.2 RGB顏色模型?編輯 1.1.3 關于顏色加法 1.1.4 顏色加權加法 1.2 HSV顏色空間 1.2.1 HSV顏色空間概念 1.2.2 HSV顏色模型 1.2.3 應用意義 1.3 顏色轉換 1.3.1 轉換方法 …

Java TCP 通信詳解:從基礎到實戰,徹底掌握面向連接的網絡編程

作為一名 Java 開發工程師&#xff0c;你一定在實際開發中遇到過需要建立穩定連接、可靠傳輸、有序通信等場景。這時&#xff0c;TCP&#xff08;Transmission Control Protocol&#xff09; 通信就成為你必須掌握的重要技能之一。TCP 是一種面向連接、可靠、基于字節流的傳輸協…

HTML5 網頁游戲設計開發——1、HTML基礎

前言 互聯網上的應用程序被稱為Web程序&#xff0c;Web引用用程序是用Web文檔&#xff08;網頁&#xff09;累表現用戶界面&#xff0c;而Web文檔都遵守HTML格式。HTML5是最新的HTML標準。之前的版本HTML4.01于1999年發布&#xff0c;小20年過去了&#xff0c;互聯網已經發聲了…

opencv圖片標注

功能使用python opencv, 將文字信息標注在圖片中同一張圖片中涉及多次標注文字大小為標注框的0.3倍使用多綫程運行import cv2 import threading import numpy as npdef draw_annotations(item, annotations):"""在圖片上繪制標注框和文本annotations: 標注列表…

矩陣SVD分解計算

對于有數學庫的時候,進行矩陣相關計算還是不復雜,但是沒有數學庫就很麻煩,利用算法實現了矩陣奇異值分解。 void decompose(const std::vector<std::vector<double>>& A, std::vector<std::vector<double>>& U, std::vector<dou…

Flutter基礎(前端教程①⑦-Column豎直-Row水平-Warp包裹-Stack堆疊)

MainAxisAlignment 是一個枚舉類&#xff0c;用于控制主軸&#xff08;Main Axis&#xff09; 方向上子組件的排列和對齊方式。MainAxisAlignment 的常用取值及效果&#xff1a;MainAxisAlignment.start子組件沿主軸的起點對齊&#xff08;Row 左對齊&#xff0c;Column 頂部對…

構建智能視頻中樞--多路RTSP轉RTMP推送模塊在軌道交通與工業應用中的技術方案探究

1?? 行業背景與技術需求&#x1f688; 軌道交通行業對視頻監控的深度依賴在現代城市軌道交通系統中&#xff0c;視頻監控已不僅僅是安防的一部分&#xff0c;更是貫穿于運營管理、車輛調度、應急指揮和安全保障的核心技術手段。列車車載監控 ——列車上普遍部署多路高清攝像頭…

【Android Studio 2025 漢化教程】

廢話不多說&#xff0c;直接上干貨。 前提&#xff1a;JeBrains系列2025版已經集成中文插件&#xff0c;用戶不需下載&#xff0c;只要設置下即可&#xff0c;但Android Studio并不內置也不提供漢化插件。需要工具&#xff1a; 1.IDEA&#xff08;其他JeBrains系列也可以&#…

網絡安全初級(前端頁面的編寫分析)

源代碼index.html<!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>登錄頁面</title><!--…

RAG項目實戰:LangChain 0.3集成 Milvus 2.5向量數據庫,構建大模型智能應用

項目背景 最近&#xff0c;有時間&#xff0c;想著動手實戰一下&#xff0c;從0到1搭建一個 RAG 系統&#xff0c;也是想通過實戰的方式來更進一步學習 RAG。因此&#xff0c;就定下了以項目實戰為主&#xff0c;書籍為輔的執行方式。&#xff08;書籍是黃佳老師著的《RAG 實戰…

docker build 和compose 學習筆記

目錄 docker build 筆記 1. 路徑解析 2. 關鍵注意事項 2. docker compose up -d 核心區別對比 常見工作流 補充說明 1. 功能區別 2. 協作關系 場景 1&#xff1a;Compose 自動調用 Build 場景 2&#xff1a;先 Build 后 Compose 3. 關鍵區別 4. 為什么需要協作&…

Java學習第六十六部分——分布式系統架構

目錄 一、前言提要 二、核心目標 三、核心組件與技術 1. 服務拆分與通信 2. 服務注冊與發現 3. 配置中心 4. 負載均衡 5. 熔斷、降級與限流 6. API 網關 7. 分布式數據管理 8. 分布式追蹤與監控 9. 容器化與編排 四、典型Java分布式技術棧組合 五、關鍵…