You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将臃肿的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 02:01:18