当前位置: 首页 > 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.lryc.cn/news/595798.html

相关文章:

  • MCP消息协议和传输协议(Java角度)
  • Apache Ignite 长事务终止机制
  • -----------------------------------事务--------------------------
  • android 12 的 aidl for HAL 开发示例
  • Apache Ignite 中的 SQL 模式(Schema)管理机制
  • Matplotlib绘制各种图参考
  • #Linux内存管理#mmap函数创立私有匿名映射的工作原理
  • 在 Ubuntu 22.04 上安装并优化 Nginx nginx入门操作 稍难,需要有一定理论 多理解 多实践
  • Debug 与 Release 版本构建详解
  • 嵌入式学习-土堆目标检测(2)-day26
  • 【AI时代速通QT】第五节:Qt Creator如何引入第三方库,以OpenCV为例
  • [2025CVPR]ViKIENet:通过虚拟密钥实例增强网络实现高效的 3D 对象检测
  • STM32-SPI全双工同步通信
  • Kotlin 作用域函数 let 的实现原理
  • 替代Oracle?金仓数据库用「敢替力」重新定义国产数据库
  • 【Android】xml和Java两种方式实现发送邮件页面
  • Windows PE文件内未用空间学习
  • 17-VRRP
  • 基于 Vue,SPringBoot开发的新能源充电桩的系统
  • ospf技术
  • 【机器学习】第四章 回归算法
  • 高层功能架构详解 - openExo
  • Flutter基础(前端教程①⑧-Text文本-Icon图标-Image图片)
  • C语言符号可见性控制与工程实践——深入理解 __attribute__((visibility)) 和 -fvisibility=hidden
  • 跨服务调用中,直接使用 MDC的上下文无法自动传递
  • Oracle 12c 创建数据库初级教程
  • 从FDTD仿真到光学神经网络:机器学习在光子器件设计中的前沿应用工坊
  • 从RAG到Agentic RAG
  • 无人机吊舱与遥控器匹配技术解析
  • 一文读懂深度模型优化器,掌握炼丹工具