一、Kotlin 與 MVVM 結合的核心優勢
-
代碼簡潔性
- 數據類(
data class
)簡化 Model 層定義,自動生成equals/hashCode/toString
- 擴展函數簡化 View 層邏輯(如點擊事件擴展)
lateinit
/by lazy
優化 ViewModel 屬性初始化
- 數據類(
-
異步處理優化
- 協程(Coroutines)替代 RxJava,輕量且代碼可讀性強
withContext(Dispatchers.IO)
切換線程,配合LiveData
更新 UI
-
響應式編程
LiveData
?+?StateFlow
實現數據雙向綁定Flow
替代LiveData
處理復雜數據流(如網絡請求重試)
-
生命周期感知
ViewModel
配合SavedStateHandle
保存狀態LifecycleOwner
簡化生命周期監聽
二、MVVM 實現細節
-
ViewModel 層
- 使用 Kotlin?
@HiltViewModel
注解依賴注入(結合 Hilt) - 協程啟動任務:
viewModelScope.launch { ... }
StateFlow
封裝業務狀態,替代可變 LiveData
- 使用 Kotlin?
-
View 層
- DataBinding 綁定布局,Kotlin 表達式簡化邏輯(如
@{user.name ?: "Guest"}
) ViewBinding
替代findViewById
,類型安全- 協程與
lifecycleScope
結合處理異步任務
- DataBinding 綁定布局,Kotlin 表達式簡化邏輯(如
-
Model 層
- 數據類定義實體,
@SerializedName
配合 Retrofit 解析 JSON - 倉庫(Repository)模式隔離數據源,Kotlin 密封類定義請求狀態(如
Result.Success/Error
)
- 數據類定義實體,
之間的關聯:
- View 持有 ViewModel:View(如 Activity、Fragment 等)會創建并持有 ViewModel 的引用,通過數據綁定機制觀察 ViewModel 中的數據變化。
- ViewModel 持有 Model:ViewModel 持有 Model 的引用,從 Model 獲取數據并處理業務邏輯,將處理后的數據暴露給 View。
- Model 不持有 View 和 ViewModel:Model 專注于數據的存儲和獲取,不依賴于 View 和 ViewModel。
三、面試高頻問題
1、ViewModel 是如何保持數據的
? ? ? ? ViewModel 使用了 Android 架構組件中的 SavedStateHandle 來保持數據。
? ? ? ? SavedStateHandle 是一個鍵值對集合,用于在配置更改(如屏幕旋轉)時保存和恢復數據。
? ? ? ?當 Activity 或 Fragment 因配置更改而銷毀重建時,ViewModel 不會被銷毀,SavedStateHandle 中的數據會被保留,從而實現數據的保持。
2、 ViewModel 是怎么做到在 Activity 銷毀重建新實例之后還能保持不變的
? ? ? ? 在 Android 中,ViewModel 的生命周期與 Activity 或 Fragment 的生命周期不同。
? ? ? ? 當 Activity 或 Fragment 因配置更改(如屏幕旋轉)而銷毀重建時,系統會自動保留 ViewModel 的實例。
? ? ? ?這是通過 ViewModelStore 來實現的,ViewModelStore 是一個存儲 ViewModel 實例的容器,Activity 或 Fragment 會持有一個 ViewModelStore 的引用。
? ? ? 當 Activity 或 Fragment 重建時,會從 ViewModelStore 中獲取之前的 ViewModel 實例,從而保證 ViewModel 中的數據不會丟失。
四、最佳實踐
- View:對應 Android 中的 Activity、Fragment、View 等,負責界面的繪制和用戶交互的處理。
- ViewModel:對應 Android 中的 ViewModel 類,負責處理業務邏輯和數據的轉換,通過 LiveData、StateFlow 等將數據暴露給 View。
- Model:對應數據的實體類(如 Kotlin 中的數據類)和數據獲取的倉庫類(Repository),負責數據的存儲和獲取。
演示代碼:
ViewModel:
@HiltViewModel
class MainViewModel @Inject constructor(private val repository: UserRepository
) : ViewModel() {private val _user = MutableStateFlow<User?>(null)val user: StateFlow<User?> = _userfun fetchUser(userId: String) {viewModelScope.launch {try {_user.value = repository.getUser(userId)} catch (e: Exception) {// 處理錯誤}}}
}
View 層(Fragment):
class MainFragment : Fragment() {private val viewModel by viewModels<MainViewModel>()override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)viewModel.user.collectAsState().observe(viewLifecycleOwner) { user ->// 更新UI}}
}
真實操作:
首先,確保在項目的?build.gradle
?中添加必要的依賴,如 ViewModel、LiveData、Kotlin 協程等:
dependencies {// ViewModel 和 LiveDataimplementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2'implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.6.2'// Kotlin 協程implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
}
Model 層
Model 層主要負責數據的定義和數據的獲取。這里以一個簡單的用戶數據為例:
// 定義用戶數據類
data class User(val id: Int, val name: String, val age: Int)// 模擬數據獲取的倉庫類
class UserRepository {// 模擬網絡請求,使用協程進行異步操作suspend fun getUser(id: Int): User {// 模擬耗時操作delay(1000)return User(id, "John Doe", 30)}
}
ViewModel 層
ViewModel 層負責處理業務邏輯,并將數據暴露給 View 層。它通過 LiveData 或 StateFlow 來實現數據的響應式更新。
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launchclass UserViewModel(private val userRepository: UserRepository) : ViewModel() {// 使用 MutableStateFlow 來存儲和更新用戶數據private val _user = MutableStateFlow<User?>(null)// 對外暴露不可變的 StateFlowval user: StateFlow<User?> = _user// 獲取用戶數據的方法fun fetchUser(id: Int) {viewModelScope.launch {try {// 調用倉庫類的方法獲取用戶數據val user = userRepository.getUser(id)// 更新 StateFlow 的值_user.value = user} catch (e: Exception) {// 處理異常e.printStackTrace()}}}
}
View 層
View 層通常是 Activity 或 Fragment,負責顯示數據和處理用戶交互。這里以 Fragment 為例:
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launchclass UserFragment : Fragment() {private val userViewModel: UserViewModel by lazy {UserViewModel(UserRepository())}override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View? {return inflater.inflate(R.layout.fragment_user, container, false)}override fun onViewCreated(view: View, savedInstanceState: Bundle?) {super.onViewCreated(view, savedInstanceState)// 啟動協程來收集 StateFlow 的數據lifecycleScope.launch {userViewModel.user.collect { user ->user?.let {// 更新 UI// 這里可以根據實際情況更新 TextView 等視圖組件// 例如:textView.text = "${it.name}, ${it.age}"}}}// 觸發數據獲取userViewModel.fetchUser(1)}
}
代碼解釋
- Model 層:
data class User
:使用 Kotlin 的數據類簡潔地定義了用戶數據結構,自動生成?equals
、hashCode
?和?toString
?方法。UserRepository
:模擬了數據的獲取過程,使用?suspend
?關鍵字和?delay
?函數模擬網絡請求的異步操作,使用協程進行異步處理。
- ViewModel 層:
MutableStateFlow
?和?StateFlow
:用于存儲和暴露用戶數據,實現數據的響應式更新。MutableStateFlow
?用于內部數據的更新,StateFlow
?用于對外暴露不可變的數據。viewModelScope.launch
:在 ViewModel 中使用協程進行異步操作,確保在 ViewModel 的生命周期內執行。當 ViewModel 被銷毀時,協程會自動取消。
- View 層:
lifecycleScope.launch
:在 Fragment 中使用協程來收集?StateFlow
?的數據,確保在 Fragment 的生命周期內執行。當 Fragment 被銷毀時,協程會自動取消。userViewModel.fetchUser(1)
:觸發數據獲取操作,調用 ViewModel 中的方法獲取用戶數據。
總結:
? ? ?Kotlin 通過協程、數據類、擴展函數等特性大幅提升了 MVVM 的開發效率和代碼質量,
? ? 面試中需重點關注異步處理、數據綁定、依賴注入及生命周期管理。