如何将臃肿的ViewModel拆分为多个小型ViewModel?
拆分依赖共享乘客列表的臃肿ViewModel方案
核心思路:状态与操作分离,共享单一数据源
既然所有功能都依赖existingPassengerList,别硬拆状态,而是把状态管理和具体业务操作分开,让每个ViewModel只干一件事。
1. 先搞个专门的状态容器ViewModel
创建PassengerStateViewModel,它唯一的职责就是管理existingPassengerList的状态,其他ViewModel都从这拿数据、更新数据:
class PassengerStateViewModel : ViewModel() { private val _existingPassengers = MutableLiveData<List<Passenger>>(emptyList()) // 对外只暴露不可变的LiveData,防止外部随意修改 val existingPassengers: LiveData<List<Passenger>> = _existingPassengers // 所有修改列表的操作都得走这个入口,保证状态变更可控 fun updatePassengers(newList: List<Passenger>) { _existingPassengers.value = newList } }
2. 按业务拆操作类ViewModel
把获取历史乘客、增删改这些操作,拆成独立的ViewModel,每个只负责自己的业务,依赖上面的状态容器拿数据:
(1)历史乘客获取ViewModel
专门负责从仓库拉取历史乘客,更新到状态容器:
class PassengerHistoryViewModel( private val stateViewModel: PassengerStateViewModel, private val passengerRepo: PassengerRepository ) : ViewModel() { fun fetchHistoryPassengers() { viewModelScope.launch { val historyList = passengerRepo.getHistoryPassengers() stateViewModel.updatePassengers(historyList) } } }
(2)乘客编辑ViewModel
只处理编辑乘客的逻辑,从状态容器拿当前列表,修改后同步回去:
class PassengerEditViewModel( private val stateViewModel: PassengerStateViewModel, private val passengerRepo: PassengerRepository ) : ViewModel() { fun editPassenger(oldPassenger: Passenger, newPassenger: Passenger) { viewModelScope.launch { val updatedList = stateViewModel.existingPassengers.value?.map { if (it.id == oldPassenger.id) newPassenger else it } ?: emptyList() // 先更新仓库,再同步状态 passengerRepo.updatePassenger(newPassenger) stateViewModel.updatePassengers(updatedList) } } }
(3)乘客增删ViewModel
专门管理添加和删除乘客的操作:
class PassengerManageViewModel( private val stateViewModel: PassengerStateViewModel, private val passengerRepo: PassengerRepository ) : ViewModel() { fun addPassenger(newPassenger: Passenger) { viewModelScope.launch { val updatedList = stateViewModel.existingPassengers.value.orEmpty() + newPassenger passengerRepo.savePassenger(newPassenger) stateViewModel.updatePassengers(updatedList) } } fun deletePassenger(passenger: Passenger) { viewModelScope.launch { val updatedList = stateViewModel.existingPassengers.value.orEmpty().filter { it.id != passenger.id } passengerRepo.deletePassenger(passenger) stateViewModel.updatePassengers(updatedList) } } }
3. Fragment里整合这些ViewModel
在Fragment里通过ViewModel工厂把状态容器注入到各个操作ViewModel里,然后观察状态容器的列表变化更新UI:
class PassengerDetailFragment : Fragment() { // 共享的状态容器ViewModel private val stateViewModel: PassengerStateViewModel by viewModels() // 其他操作ViewModel通过工厂注入状态容器 private val historyViewModel: PassengerHistoryViewModel by viewModels { PassengerHistoryViewModelFactory(stateViewModel, passengerRepo) } private val editViewModel: PassengerEditViewModel by viewModels { PassengerEditViewModelFactory(stateViewModel, passengerRepo) } private val manageViewModel: PassengerManageViewModel by viewModels { PassengerManageViewModelFactory(stateViewModel, passengerRepo) } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) // 只需要观察状态容器的列表变化,就能更新所有UI stateViewModel.existingPassengers.observe(viewLifecycleOwner) { passengers -> // 更新RecyclerView之类的UI组件 } } }
几个要注意的点
- 绝对不能让操作ViewModel直接修改状态容器里的列表,必须通过
updatePassengers方法,不然容易出现数据不一致的问题。 - 如果用Compose的话,把LiveData换成StateFlow会更顺手,配合
collectAsState即可。 - 所有依赖状态容器的ViewModel,一定要用工厂注入,别在代码里硬new,避免耦合过死。
内容的提问来源于stack exchange,提问作者Maede Jalali
相关产品推荐
相关产品推荐

