news 2026/4/23 9:18:18

ViewModel、LiveData的使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
ViewModel、LiveData的使用

6.2.1 ViewModel 的创建与获取

方式1:使用 by viewModels 委托(推荐)

classMainActivity:AppCompatActivity(){// 使用 by viewModels 委托创建 ViewModelprivatevalviewModel:UserViewModelbyviewModels()overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// 直接使用 viewModelviewModel.userData.observe(this){user->updateUI(user)}}}

方式2:使用 ViewModelProvider 手动创建

classMainActivity:AppCompatActivity(){privatelateinitvarviewModel:UserViewModeloverridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// 手动创建 ViewModelviewModel=ViewModelProvider(this)[UserViewModel::class.java]viewModel.userData.observe(this){user->updateUI(user)}}}

方式3:Fragment 中获取 Activity 的 ViewModel

classUserFragment:Fragment(){// 获取 Activity 的 ViewModel(共享 ViewModel)privatevalviewModel:UserViewModelbyactivityViewModels()overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super.onViewCreated(view,savedInstanceState)viewModel.userData.observe(viewLifecycleOwner){user->updateUI(user)}}}

方式4:ViewModelProvider.Factory带参数的 ViewModel 创建

// 定义带参数的 ViewModelclassUserViewModel(privatevaluserId:String,privatevalrepository:UserRepository):ViewModel(){privateval_userData=MutableLiveData<User>()valuserData:LiveData<User>=_userDatainit{loadUserData()}privatefunloadUserData(){viewModelScope.launch{valuser=repository.getUser(userId)_userData.value=user}}}// 定义 FactoryclassUserViewModelFactory(privatevaluserId:String,privatevalrepository:UserRepository):ViewModelProvider.Factory{overridefun<T:ViewModel>create(modelClass:Class<T>):T{if(modelClass.isAssignableFrom(UserViewModel::class.java)){@Suppress("UNCHECKED_CAST")returnUserViewModel(userId,repository)asT}throwIllegalArgumentException("Unknown ViewModel class")}}// 使用 Factory 创建 ViewModelclassMainActivity:AppCompatActivity(){privatevalviewModel:UserViewModelbyviewModels{UserViewModelFactory(userId="U001",repository=UserRepository())}overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)viewModel.userData.observe(this){user->updateUI(user)}}}

方式五:使用 Hilt 依赖注入

// 使用 Hilt 注入 ViewModel@HiltViewModelclassUserViewModel@Injectconstructor(privatevalrepository:UserRepository):ViewModel(){privateval_userData=MutableLiveData<User>()valuserData:LiveData<User>=_userData}// 在 Activity 中使用@AndroidEntryPointclassMainActivity:AppCompatActivity(){privatevalviewModel:UserViewModelbyviewModels()overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)viewModel.userData.observe(this){user->updateUI(user)}}}

6.2.3 ViewModel 与 Fragment 共享数据

场景:Activity 和多个 Fragment 共享数据

// ActivityclassMainActivity:AppCompatActivity(){privatevalviewModel:SharedViewModelbyviewModels()overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)// Activity 可以修改数据viewModel.updateUser(User("1","张三","zhang@example.com"))}}// Fragment1classUserListFragment:Fragment(){// 获取 Activity 的 ViewModelprivatevalviewModel:SharedViewModelbyactivityViewModels()overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super.onViewCreated(view,savedInstanceState)viewModel.userList.observe(viewLifecycleOwner){users->updateUI(users)}}}// Fragment2classUserDetailFragment:Fragment(){// 获取 Activity 的 ViewModelprivatevalviewModel:SharedViewModelbyactivityViewModels()overridefunonViewCreated(view:View,savedInstanceState:Bundle?){super.onViewCreated(view,savedInstanceState)viewModel.selectedUser.observe(viewLifecycleOwner){user->updateUI(user)}}}// 共享的 ViewModelclassSharedViewModel:ViewModel(){privateval_userList=MutableLiveData<List<User>>()valuserList:LiveData<List<User>>=_userListprivateval_selectedUser=MutableLiveData<User>()valselectedUser:LiveData<User>=_selectedUserfunupdateUser(user:User){_selectedUser.value=user}funupdateUserList(users:List<User>){_userList.value=users}}

6.3.1 ViewModel 与协程集成 viewModelScope

viewModelScope - ViewModel 生命周期感知的协程作用域

classUserViewModel(privatevalrepository:UserRepository):ViewModel(){privateval_userData=MutableLiveData<User>()valuserData:LiveData<User>=_userDatainit{// 使用 viewModelScope 启动协程viewModelScope.launch{// 当 ViewModel 销毁时,协程自动取消valuser=repository.getUser()_userData.value=user}}funloadUser(userId:String){viewModelScope.launch{valuser=repository.getUser(userId)_userData.value=user}}overridefunonCleared(){super.onCleared()// ViewModel 销毁时,viewModelScope 中的所有协程自动取消println("ViewModel 销毁,协程已取消")}}

viewModelScope 的特性

特性说明
生命周期与 ViewModel 绑定
自动取消ViewModel 销毁时自动取消协程
调度器默认使用 Dispatchers.Main.immediate
异常处理未捕获的异常会传播到父协程

6.3.2 协程取消机制

协程取消的示例

classUserViewModel(privatevalrepository:UserRepository):ViewModel(){privateval_userData=MutableLiveData<User>()valuserData:LiveData<User>=_userDataprivateval_loading=MutableLiveData<Boolean>()valloading:LiveData<Boolean>=_loadingfunloadUser(userId:String){viewModelScope.launch{_loading.value=truetry{// 如果 ViewModel 销毁,这里会抛出 CancellationExceptionvaluser=repository.getUser(userId)_userData.value=user}catch(e:Exception){if(e!isCancellationException){// 处理业务异常,忽略取消异常println("加载用户失败:${e.message}")}}finally{_loading.value=false}}}overridefunonCleared(){super.onCleared()// 所有 viewModelScope 中的协程会被取消}}

使用 SupervisorJob 避免子协程相互影响

classUserViewModel(privatevalrepository:UserRepository):ViewModel(){privateval_userData=MutableLiveData<User>()valuserData:LiveData<User>=_userDataprivateval_orderList=MutableLiveData<List<Order>>()valorderList:LiveData<List<Order>>=_orderListfunloadAllData(userId:String){viewModelScope.launch{// 使用 SupervisorJob,子协程失败不影响其他子协程valuserDeferred=async{repository.getUser(userId)}valordersDeferred=async{repository.getOrders(userId)}try{valuser=userDeferred.await()_userData.value=user}catch(e:Exception){println("加载用户失败:${e.message}")}try{valorders=ordersDeferred.await()_orderList.value=orders}catch(e:Exception){println("加载订单失败:${e.message}")}}}}

7.3.1 map 转换

map - 转换 LiveData 的数据类型

classUserViewModel:ViewModel(){privateval_userData=MutableLiveData<User>()valuserData:LiveData<User>=_userData// 使用 map 转换数据valuserName:LiveData<String>=_userData.map{user->user.name}valuserEmail:LiveData<String>=_userData.map{user->user.email}valuserGreeting:LiveData<String>=_userData.map{user->"你好,${user.name}!"}funloadUser(){viewModelScope.launch{valuser=userRepository.getUser()_userData.value=user}}}###7.3.2switchMap 转换**switchMap-动态切换 LiveData**: ```kotlinclassUserViewModel(privatevalrepository:UserRepository):ViewModel(){privateval_userId=MutableLiveData<String>()valuserId:LiveData<String>=_userId// 使用 switchMap 动态切换 LiveDatavaluserData:LiveData<User>=_userId.switchMap{userId->repository.getUserLiveData(userId)}funloadUser(userId:String){_userId.value=userId}}**switchMap vs map 对比**: | 特性 | map | switchMap | |------|-----|-----------| |**转换类型**| 数据类型转换 | LiveData 切换 | |**触发条件**| 源 LiveData 更新时 | 源 LiveData 更新时 | |**返回值**| 单个值 | 新的 LiveData | |**使用场景**| 简单的数据转换 | 动态数据加载 | ###7.3.3MediatorLiveData 合并多个数据源**MediatorLiveData-合并多个 LiveData**: ```kotlinclassUserViewModel:ViewModel(){privateval_userData=MutableLiveData<User>()valuserData:LiveData<User>=_userDataprivateval_orderData=MutableLiveData<List<Order>>()valorderData:LiveData<List<Order>>=_orderDataprivateval_productData=MutableLiveData<List<Product>>()valproductData:LiveData<List<Product>>=_productData// 合并多个 LiveDataprivateval_dashboardData=MediatorLiveData<DashboardData>()valdashboardData:LiveData<DashboardData>=_dashboardDatainit{// 添加源 LiveData_dashboardData.addSource(_userData){user->updateDashboardData()}_dashboardData.addSource(_orderData){orders->updateDashboardData()}_dashboardData.addSource(_productData){products->updateDashboardData()}}privatefunupdateDashboardData(){valuser=_userData.valuevalorders=_orderData.value?:emptyList()valproducts=_productData.value?:emptyList()_dashboardData.value=DashboardData(user=user,orderCount=orders.size,productCount=products.size)}funloadDashboard(){viewModelScope.launch{valuser=userRepository.getUser()_userData.value=uservalorders=orderRepository.getOrders()_orderData.value=ordersvalproducts=productRepository.getProducts()_productData.value=products}}}dataclassDashboardData(valuser:User?,valorderCount:Int,valproductCount:Int)

7.4.3 使用 SharedFlow 替代 LiveData(见第21章)

SharedFlow vs LiveData

// SharedFlow - 更现代的响应式组件classMyViewModel:ViewModel(){// SharedFlow 支持多个观察者privateval_events=MutableSharedFlow<Event>()valevents:SharedFlow<Event>=_events.asSharedFlow()funsendEvent(event:Event){viewModelScope.launch{_events.emit(event)}}}// 使用classMainActivity:AppCompatActivity(){privatevalviewModel:MyViewModelbyviewModels()overridefunonCreate(savedInstanceState:Bundle?){super.onCreate(savedInstanceState)lifecycleScope.launch{viewModel.events.collect{event->handleEvent(event)}}}}

核心要点回顾

  1. ViewModel 的设计理念

    • 配置变更数据保持
    • 分离视图逻辑与业务逻辑
    • ViewModel 的生命周期
  2. ViewModel 基础用法

    • ViewModel 的创建与获取
    • ViewModelProvider.Factory
    • ViewModel 与 Fragment 共享数据
  3. ViewModel 与协程集成

    • viewModelScope 的使用
    • 协程取消机制
    • SupervisorJob 的使用
      LiveData 转换操作
    • map 转换
    • switchMap 动态切换
    • MediatorLiveData 合并多个数据源
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 9:17:17

QtScrcpy深度解析:突破Android设备管理与批量控制的技术方案

QtScrcpy深度解析&#xff1a;突破Android设备管理与批量控制的技术方案 【免费下载链接】QtScrcpy Android real-time display control software 项目地址: https://gitcode.com/GitHub_Trending/qt/QtScrcpy 作为一名Android开发者或测试工程师&#xff0c;你是否经常…

作者头像 李华
网站建设 2026/4/23 9:17:17

Rust泛型编程:从零成本抽象到极致性能

1. 为什么要用泛型 用同一套逻辑处理不同类型数据&#xff0c;避免为每种类型重复写函数减少冗余代码&#xff0c;提升表达能力&#xff0c;是一种多态实现 无泛型&#xff08;啰嗦版&#xff09; fn add_i8(a:i8, b:i8) -> i8 { a b } fn add_i32(a:i32, b:i32) -> i32…

作者头像 李华
网站建设 2026/4/23 9:12:45

python可迭代对象,应用 在断言

文章目录前言一、any()、all()1. any()、all()2. python中的假值3.常见用法二、map()、filter()1.map()2.filter()三、生成器表达式总结前言 python中&#xff0c;涉及到批量数据的断言时。 1&#xff09;经常使用的内置函数。 提示&#xff1a;以下是本篇文章正文内容&#x…

作者头像 李华
网站建设 2026/4/23 9:09:21

xhs库:3大技术突破实现小红书数据采集的终极实战指南

xhs库&#xff1a;3大技术突破实现小红书数据采集的终极实战指南 【免费下载链接】xhs 基于小红书 Web 端进行的请求封装。https://reajason.github.io/xhs/ 项目地址: https://gitcode.com/gh_mirrors/xh/xhs 在当今数据驱动的商业决策环境中&#xff0c;小红书平台蕴含…

作者头像 李华
网站建设 2026/4/23 9:04:32

CosyVoice3情感控制全解析:如何调整语音的情感强度和复合情感

CosyVoice3情感控制全解析&#xff1a;如何调整语音的情感强度和复合情感 1. 为什么需要情感语音合成&#xff1f; 在游戏开发、有声读物制作和虚拟助手交互中&#xff0c;单纯的文字转语音往往无法满足需求。一个优秀的NPC对话系统需要能够根据剧情发展调整语音情感&#xf…

作者头像 李华