当前位置: 首页 > news >正文

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.xdnf.cn/news/108721.html

相关文章:

  • 按照文本每行匹配文件复制到指定位置
  • CONDA:用于 Co-Salient 目标检测的压缩深度关联学习(总结)
  • 开源 RAG 引擎:文档理解精准、检索高效、可视化干预灵活,一站式搞定
  • Kappa架构:简化大数据实时流处理的创新方案
  • 【Luogu】动态规划二
  • 2025.4.27机器学习笔记:文献阅读
  • 类和对象(中)
  • Spring AI 会话记忆(笔记)
  • 【3.2】pod详解—— Pod的相位(phase)状态(status)
  • Linux常用指令
  • 小刚说C语言刷题——1338求圆环的面积
  • C++二分法详解
  • el-table 目录树列表本地实现模糊查询
  • Linux部署Redis主从
  • 天梯-零头就抹了吧
  • 实操Obsidian+Ollama+deepseek构建本地知识库
  • C语言五子棋项目
  • [计算机科学#1]:计算机的前世今生,从算盘到IBM的演变之路
  • flex布局说明
  • 百万点数组下memset、memcpy与for循环效率对比及原理分析
  • 经典算法 小数点后的第n位
  • 语音合成之四基于LLM的语音合成
  • Sql刷题日志(day5)
  • JVM理解(通俗易懂)
  • 2025年渗透测试面试题总结-拷打题库14(题目+回答)
  • 时间自动填写——电子表格公式的遗憾(DeepSeek)
  • A13 自定义系统服务使用总结
  • Kafka集群
  • ABP-Book Store Application中文讲解 - Part 0:开发环境搭建
  • 意见反馈留言二维码制作