kotlin與MVVM結合使用總結(一)

一、Kotlin 與 MVVM 結合的核心優勢

  1. 代碼簡潔性

    • 數據類(data class)簡化 Model 層定義,自動生成equals/hashCode/toString
    • 擴展函數簡化 View 層邏輯(如點擊事件擴展)
    • lateinit/by lazy優化 ViewModel 屬性初始化
  2. 異步處理優化

    • 協程(Coroutines)替代 RxJava,輕量且代碼可讀性強
    • withContext(Dispatchers.IO)切換線程,配合LiveData更新 UI
  3. 響應式編程

    • LiveData?+?StateFlow實現數據雙向綁定
    • Flow替代LiveData處理復雜數據流(如網絡請求重試)
  4. 生命周期感知

    • ViewModel配合SavedStateHandle保存狀態
    • LifecycleOwner簡化生命周期監聽

二、MVVM 實現細節

  1. ViewModel 層

    • 使用 Kotlin?@HiltViewModel注解依賴注入(結合 Hilt)
    • 協程啟動任務:viewModelScope.launch { ... }
    • StateFlow封裝業務狀態,替代可變 LiveData
  2. View 層

    • DataBinding 綁定布局,Kotlin 表達式簡化邏輯(如@{user.name ?: "Guest"}
    • ViewBinding替代findViewById,類型安全
    • 協程與lifecycleScope結合處理異步任務
  3. 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 的數據類簡潔地定義了用戶數據結構,自動生成?equalshashCode?和?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 的開發效率和代碼質量,

? ? 面試中需重點關注異步處理、數據綁定、依賴注入及生命周期管理。

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

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

相關文章

視頻分析設備平臺EasyCVR安防視頻小知識:安防監控常見故障精準排查方法

隨著安防監控技術的飛速發展&#xff0c;監控系統已經成為現代安防體系中不可或缺的核心組成部分&#xff0c;廣泛應用于安防監控、交通管理、工業自動化等多個領域。然而&#xff0c;監控系統的穩定運行高度依賴于設備的正確配置、線路的可靠連接以及電源的穩定供電。在實際應…

【DeepSeek 學習推理】Llumnix: Dynamic Scheduling for Large Language Model Serving實驗部分

6.1 實驗設置 測試平臺。我們使用阿里云上的16-GPU集群&#xff08;包含4個GPU虛擬機&#xff0c;類型為ecs.gn7i-c32g1.32xlarge&#xff09;。每臺虛擬機配備4個NVIDIA A10&#xff08;24 GB&#xff09;GPU&#xff08;通過PCI-e 4.0連接&#xff09;、128個vCPU、752 GB內…

如何利用深度學習進行交通流量預測與疏導

傳統的交通管理方法&#xff0c;諸如固定的信號燈配時方案、基于經驗的警力部署等&#xff0c;在面對現代城市如此復雜多變的交通狀況時&#xff0c;已然顯得捉襟見肘&#xff0c;難以滿足高效交通管理的需求。 在此背景下&#xff0c;準確的交通流量預測便成為了破解交通擁堵難…

LSTM-GAN生成數據技術

1. 項目概述 本項目利用生成對抗網絡&#xff08;GAN&#xff09;技術來填補時間序列數據中的缺失值。項目實現了兩種不同的GAN模型&#xff1a;基于LSTM的GAN&#xff08;LSTM-GAN&#xff09;和基于多層感知機的GAN&#xff08;MLP-GAN&#xff09;&#xff0c;并對兩種模型…

CMake 入門指南:從零開始配置你的第一個項目

目錄 一、CMake 是什么&#xff0c;為什么要使用 CMake 二、CMakeLists.txt 文件結構與簡單示例 三、進階的CMake 四、靜態庫與動態庫生成及其使用 五、注釋的語法 六、 set、list、message 三個常用的 CMake 函數與命令 七、CMake 的控制語句以及自定義宏/函數 八、為S…

多線程出bug不知道如何調試?java線程幾種常見狀態

當你的多線程代碼結構很復雜的時候很難找出bug的原因所在&#xff0c;此時我們可以使用getState()方法獲取該線程當前的狀態&#xff0c;通過觀察其狀態是阻塞了還是因為沒有啟動等原因導致的。 狀態描述NEW安排了工作&#xff0c;還未開始行動RUNNABLE可工作的&#xff0c;又…

Spark(20)spark和Hadoop的區別

Apache Spark 和 Apache Hadoop 都是廣泛使用的開源大數據處理框架&#xff0c;但它們在設計理念、架構、性能和適用場景等方面存在顯著區別。以下是它們的主要區別&#xff1a; ### **1. 架構設計** - **Hadoop**&#xff1a; - **HDFS&#xff08;Hadoop Distributed File…

【redis】哨兵模式

Redis主從模式雖然支持數據備份與讀寫分離&#xff0c;但存在三大核心缺陷&#xff1a;1. 故障切換依賴人工&#xff08;主節點宕機需手動提升從節點&#xff09;&#xff1b;2. 監控能力缺失&#xff08;無法自動檢測節點異常&#xff09;&#xff1b;3. 腦裂風險&#xff08;…

Spark-Streaming

找出所有有效數據&#xff0c;要求電話號碼為11位&#xff0c;但只要列中沒有空值就算有效數據。 按地址分類&#xff0c;輸出條數最多的前20個地址及其數據。 代碼講解&#xff1a; 導包和聲明對象&#xff0c;設置Spark配置對象和SparkContext對象。 使用Spark SQL語言進行數…

Sentinel源碼—9.限流算法的實現對比一

大綱 1.漏桶算法的實現對比 (1)普通思路的漏桶算法實現 (2)節省線程的漏桶算法實現 (3)Sentinel中的漏桶算法實現 (4)Sentinel中的漏桶算法與普通漏桶算法的區別 (5)Sentinel中的漏桶算法存在的問題 2.令牌桶算法的實現對比 (1)普通思路的令牌桶算法實現 (2)節省線程的…

Redis 詳解:安裝、數據類型、事務、配置、持久化、訂閱/發布、主從復制、哨兵機制、緩存

目錄 Redis 安裝與數據類型 安裝指南 Windows Linux 性能測試 基本知識 數據類型 String List&#xff08;雙向列表&#xff09; Set&#xff08;集合&#xff09; Hash&#xff08;哈希&#xff09; Zset&#xff08;有序集合&#xff09; 高級功能 地理位置&am…

Docker配置帶證書的遠程訪問監聽

一、生成證書和密鑰 1、準備證書目錄和生成CA證書 # 創建證書目錄 mkdir -p /etc/docker/tls cd /etc/docker/tls # 生成CA密鑰和證書 openssl req -x509 -newkey rsa:4096 -keyout ca-key.pem \ -out ca-cert.pem -days 365 -nodes -subj "/CNDocker CA" 2、為…

MCP接入方式介紹

上一篇文章&#xff0c;我們介紹了MCP是什么以及MCP的使用。 MCP是什么&#xff0c;MCP的使用 接下來&#xff0c;我們來詳細介紹一下MCP的接入 先看官網的架構圖 上圖的MCP 服務 A、MCP 服務 B、MCP 服務 C是可以運行在你的本地計算機&#xff08;本地服務器方式&#xff…

關于Agent的簡單構建和分享

前言&#xff1a;Agent 具備自主性、環境感知能力和決策執行能力&#xff0c;能夠根據環境的變化自動調整行為&#xff0c;以實現特定的目標。 一、Agent 的原理 Agent(智能體)被提出時&#xff0c;具有四大能力 感知、分析、決策和執行。是一種能夠在特定環境中自主行動、感…

Gitlab runner 安裝和注冊

Gitlab Runner GitLab Runner是一個用于運行GitLab CI/CD流水線作業的軟件包&#xff0c;由GitLab官方開發&#xff0c;完全開源。你可以在很多主流的系統環境或平臺上安裝它&#xff0c;如Linux、macOS、Windows和Kubernetes。如果你熟悉Jenkins 的話&#xff0c;你可以把它…

精益數據分析(18/126):權衡數據運用,精準把握創業方向

精益數據分析&#xff08;18/126&#xff09;&#xff1a;權衡數據運用&#xff0c;精準把握創業方向 大家好&#xff01;一直以來&#xff0c;我都希望能和大家在創業與數據分析的領域共同探索、共同進步。今天&#xff0c;我們繼續深入研讀《精益數據分析》&#xff0c;探討…

Git技術詳解:從核心原理到實際應用

Git技術詳解&#xff1a;從核心原理到實際應用 一、Git的本質與核心價值 Git是由Linux之父Linus Torvalds在2005年開發的分布式版本控制系統&#xff0c;其核心功能是通過記錄文件變更歷史&#xff0c;幫助開發者實現以下目標&#xff1a; 版本回溯&#xff1a;隨時恢復到項…

Java從入門到“放棄”(精通)之旅——String類⑩

Java從入門到“放棄”&#xff08;精通&#xff09;之旅&#x1f680;——String類⑩ 前言 在Java編程中&#xff0c;String類是最常用也是最重要的類之一。無論是日常開發還是面試&#xff0c;對String類的深入理解都是必不可少的。 1. String類的重要性 在C語言中&#xf…

抓取淘寶數據RPA--影刀

最近用了一下RPA軟件&#xff0c;挑了影刀&#xff0c;發現很無腦也很簡單&#xff0c;其語法大概是JAVA和PYTHON的混合體&#xff0c;如果懂爬蟲的話&#xff0c;學這個軟件就快的很&#xff0c;看了一下官方的教程&#xff0c;對于有基礎的人來說很有點枯燥&#xff0c;但又不…

docker部署seafile修改默認端口并安裝配置onlyoffice實現在線編輯

背景 有很多場景會用到類似seafile功能的需求&#xff0c;比如&#xff1a; 在內網中傳輸和共享文件個人部署私人網盤文檔協同在線編輯寫筆記… 這些功能seafile均有實現&#xff0c;并且社區版提供的功能基本可以滿足個人或者小型團隊的日常需求 問題 由于主機的80和443端…