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)}}}}核心要点回顾
ViewModel 的设计理念
- 配置变更数据保持
- 分离视图逻辑与业务逻辑
- ViewModel 的生命周期
ViewModel 基础用法
- ViewModel 的创建与获取
- ViewModelProvider.Factory
- ViewModel 与 Fragment 共享数据
ViewModel 与协程集成
- viewModelScope 的使用
- 协程取消机制
- SupervisorJob 的使用
LiveData 转换操作 - map 转换
- switchMap 动态切换
- MediatorLiveData 合并多个数据源