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

Android ViewModel 深度解析:原理、使用与最佳实践

一、ViewModel 概述

ViewModel 是 Android Jetpack 架构组件中的重要一员,专门为解决 Activity 和 Fragment 中的 UI 数据管理问题而设计。它的核心目标是:

  1. 管理 UI 相关数据:以生命周期感知的方式保存和管理数据

  2. 解决配置变更问题:在屏幕旋转等配置更改时保留数据

  3. 避免内存泄漏:自动清理资源,防止 Activity/Fragment 引用泄漏

    // 基本ViewModel类定义
    class MyViewModel : ViewModel() {// 数据将在此保存var counter = 0
    }

    二、ViewModel 生命周期

    理解 ViewModel 的生命周期是其正确使用的关键:

 

  • ViewModel 的生命周期比创建它的 Activity/Fragment 更长

  • 在 Activity 完成(finish)时才会清除

  • 屏幕旋转等配置变化不会导致重建

    class MainActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)// 获取ViewModel实例val model: MyViewModel by viewModels()}
    }

    三、ViewModel 的基本使用

    1. 添加依赖

    首先在 build.gradle 中添加依赖:

    dependencies {implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2"// 如果使用ViewModel带SavedStateimplementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:2.6.2"
    }

    2. 创建 ViewModel 类

    class UserViewModel : ViewModel() {private val _users = MutableLiveData<List<User>>()val users: LiveData<List<User>> = _usersinit {loadUsers()}private fun loadUsers() {// 模拟数据加载_users.value = listOf(User("张三"), User("李四"))}
    }

    3. 在 Activity/Fragment 中使用

class UserActivity : AppCompatActivity() {private val userViewModel: UserViewModel by viewModels()override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_user)userViewModel.users.observe(this) { users ->// 更新UIupdateUserList(users)}}
}

四、ViewModel 的高级特性

1. ViewModel 带参数

如果需要传递参数给 ViewModel,可以使用 ViewModelProvider.Factory:

class UserViewModel(private val userId: String) : ViewModel() {// ...
}class UserViewModelFactory(private val userId: String) : ViewModelProvider.Factory {override fun <T : ViewModel> create(modelClass: Class<T>): T {return UserViewModel(userId) as T}
}// 使用
val factory = UserViewModelFactory("123")
val viewModel = ViewModelProvider(this, factory).get(UserViewModel::class.java)

2. SavedStateHandle

处理进程死亡后恢复数据:

class SavedStateViewModel(private val state: SavedStateHandle) : ViewModel() {val counter: LiveData<Int> = state.getLiveData("counter", 0)fun increment() {state["counter"] = (counter.value ?: 0) + 1}
}

3. 在 Fragment 间共享数据

class SharedViewModel : ViewModel() {val selectedItem = MutableLiveData<Item>()fun select(item: Item) {selectedItem.value = item}
}// FragmentA
val model: SharedViewModel by activityViewModels()// FragmentB
val model: SharedViewModel by activityViewModels()

 

五、ViewModel 最佳实践

随着 Jetpack 组件的不断演进,ViewModel 也在持续增强功能(如与 Hilt 的集成、更完善的状态保存机制等),值得开发者持续关注和学习。

  1. 职责单一:每个 ViewModel 应只负责一个屏幕或功能模块

  2. 避免引用 Context:ViewModel 不应持有 Activity/Fragment 的引用

  3. 合理使用 LiveData:暴露不可变的 LiveData,内部使用 MutableLiveData

  4. 结合 Repository:数据操作应委托给 Repository 层

  5. 测试友好:ViewModel 应易于单元测试

    // 良好结构的ViewModel示例
    class OrderViewModel(private val orderRepository: OrderRepository,private val savedStateHandle: SavedStateHandle
    ) : ViewModel() {private val _order = MutableLiveData<Order>()val order: LiveData<Order> = _orderprivate val _loading = MutableLiveData<Boolean>()val loading: LiveData<Boolean> = _loadingfun loadOrder(orderId: String) {_loading.value = trueviewModelScope.launch {try {_order.value = orderRepository.getOrder(orderId)} catch (e: Exception) {// 处理错误} finally {_loading.value = false}}}
    }

    六、常见问题与解决方案

    1. ViewModel 内存泄漏

    问题:在 ViewModel 中持有 Activity/Fragment 引用
    解决:使用 Application Context 或完全避免 Context

    2. 数据重复加载

    问题:每次配置变更都重新加载数据
    解决:在 ViewModel 中缓存数据

    class MyViewModel : ViewModel() {private var cachedData: List<Data>? = nullfun getData(): LiveData<List<Data>> {if (cachedData == null) {loadData()}return Transformations.map(_source) { it }}
    }

    3. 测试困难

    解决:依赖注入和接口抽象

    class MyViewModel(private val dataSource: DataSourceInterface
    ) : ViewModel() {// ...
    }// 测试时可以传入Mock实现

    七、ViewModel 与协程

    ViewModel 内置了 viewModelScope,便于协程管理:

    class CoroutineViewModel : ViewModel() {fun fetchData() {viewModelScope.launch {try {val data = repository.fetchData()_uiState.value = UiState.Success(data)} catch (e: Exception) {_uiState.value = UiState.Error(e)}}}
    }

    结语

    ViewModel 是现代 Android 开发中不可或缺的架构组件,它优雅地解决了 UI 控制器(Activity/Fragment)中数据管理的难题。通过合理使用 ViewModel,开发者可以:

  6. 构建更健壮、更易维护的应用程序

  7. 提高代码的可测试性

  8. 减少内存泄漏的风险

  9. 提供更好的用户体验

http://www.xdnf.cn/news/1166617.html

相关文章:

  • Redis——Redis进阶命令集详解(下)
  • Docker Compose UI远程访问教程:结合贝锐花生壳实现内网穿透
  • Qt中QObject类的核心作用与使用
  • C++函数 vs Go函数
  • Qt基本控件使用:按钮、标签、文本框等
  • 【打怪升级 - 01】保姆级机器视觉入门指南:硬件选型 + CUDA/cuDNN/Miniconda/PyTorch 安装全流程(附版本匹配秘籍)
  • Kotlin多线程调试
  • freertos关键函数理解 uxListRemove
  • 拼多多视觉算法面试30问全景精解
  • 【AI时代速通QT】第五节:Qt Creator如何引入第三方库,以OpenCV为例
  • 《汇编语言:基于X86处理器》第9章 字符串和数组(2)
  • 库制作与原理
  • Vue 3 面试题全套题库
  • Elasticsearch安装指南
  • 【集群】MySQL的主从复制了解吗?会有延迟吗,原因是什么?
  • AngularJS 动画
  • RabbitMQ--批量处理
  • Linux 内核与底层开发
  • Axios 二次封装
  • 用org.apache.pdfbox 转换 PDF 到 图片格式
  • EMA《2025-2028年药品监管中的数据与AI 1.3版》信息分析
  • OEC 刷机Armbain 25.05后配置说明
  • 扣子Coze智能体实战:自动化拆解抖音对标账号,输出完整分析报告(喂饭级教程)
  • Java 大视界 -- Java 大数据在智能医疗医疗设备维护与管理中的应用(358)
  • Apache Ignite 中乐观事务(OPTIMISTIC Transactions)的工作机制
  • Rabbit安装
  • 全星FMEA软件系统:FMEA、PC、PFD一体化管理的智能解决方案
  • python中 tqdm ,itertuples 是什么
  • ucharts 搭配uniapp 自定义x轴文字 实现截取显示
  • Vue开发常用