干净的体系结构:在Android上有多个UseCases的ViewModel

问题描述:

这是一个架构问题,而不是一个修复问题的问题。干净的体系结构:在Android上有多个UseCases的ViewModel

让我们假设这个应用程序允许用户将公共汽车和/或巴士站标记为收藏夹。我的问题是,如果我有一个ViewModel两个UseCases或我应该建立一个封装当前逻辑的UseCase?

也为这个问题的一部分,我不能完全肯定我应该公开的组合数据的UI层的方式(见favouritesExposedLiveData

预先感谢任何反馈意见是值得欢迎的,这是我ViewModel你可以假设每个UseCase从数据源传递正确的数据。

open class FavouritesViewModel @Inject internal constructor(
      private val getFavouriteStationsUseCase: GetFavouriteStationsUseCase, 
      private val getFavouriteBusesUseCase: GetFavouriteBusesUseCase, 
      private val favouriteMapper: FavouriteMapper, 
      private val busMapper: BusMapper, 
      private val stationMapper: StationMapper) : ViewModel() { 

     private val favouriteBusesLiveData: MutableLiveData<Resource<List<BusView>>> = MutableLiveData() 
     private val favouriteStationsLiveData: MutableLiveData<Resource<List<StationView>>> = MutableLiveData() 

     private lateinit var favouritesMediatorLiveData: MediatorLiveData<List<FavouriteView>> 
     private lateinit var favouritesExposedLiveData: LiveData<Resource<List<FavouriteView>>> 

     init { 
      fetchFavourites() 
     } 

     override fun onCleared() { 
      getFavouriteStationsUseCase.dispose() 
      getFavouriteBusesUseCase.dispose() 
      super.onCleared() 
     } 

     fun getFavourites(): LiveData<Resource<List<FavouriteView>>> { 
      return favouritesExposedLiveData 
     } 

     private fun fetchFavourites() { 
      favouritesMediatorLiveData.addSource(favouriteStationsLiveData, { favouriteStationListResource -> 
       if (favouriteStationListResource?.status == ResourceState.SUCCESS) { 
        favouriteStationListResource.data?.map { 
         favouriteMapper.mapFromView(it) 
        } 
       } 
      }) 

      favouritesMediatorLiveData.addSource(favouriteBusesLiveData, { favouriteBusesListResource -> 
       if (favouriteBusesListResource?.status == ResourceState.SUCCESS) { 
        favouriteBusesListResource.data?.map { 
         favouriteMapper.mapFromView(it) 
        } 
       } 
      }) 

      getFavouriteStationsUseCase.execute(FavouriteStationsSubscriber()) 
      getFavouriteBusesUseCase.execute(FavouriteBusesSubscriber()) 
     } 

     inner class FavouriteStationsSubscriber : DisposableSubscriber<List<Station>>() { 
      override fun onComplete() {} 

      override fun onNext(t: List<Station>) { 
       favouriteStationsLiveData.postValue(Resource(ResourceState.SUCCESS, t.map { stationMapper.mapToView(it) }, null)) 
      } 

      override fun onError(exception: Throwable) { 
       favouriteStationsLiveData.postValue(Resource(ResourceState.ERROR, null, exception.message)) 
      } 

     } 

     inner class FavouriteBusesSubscriber : DisposableSubscriber<List<Bus>>() { 
      override fun onComplete() {} 

      override fun onNext(t: List<Bus>) { 
       favouriteBusesLiveData.postValue(Resource(ResourceState.SUCCESS, t.map { busMapper.mapToView(it) }, null)) 
      } 

      override fun onError(exception: Throwable) { 
       favouriteBusesLiveData.postValue(Resource(ResourceState.ERROR, null, exception.message)) 
      } 

     } 
    } 

注:目前MediatorLiveDatafavouritesMediatorLiveData)没有在这个时候数据绑定回favouritesExposedLiveData,因为,我不知道这是要走正确的方式)。

ViewModel的重点在于它是视图使用的模型。它应该尽可能接近。除非你在同一个视图列表中显示车站和公共汽车(否则),否则,它们是单独的视图,应该有不同的模型。

+0

感谢您的反馈,但您并未真正回答这个问题,是的,我想同时显示巴士和车站(标记为收藏夹)。 –

理想情况下,一个ViewModel只能有其视图的视图状态。通过使用MediatorLiveData,您可以将所有状态来源聚合为代表随时间变化的视图状态。

什么你可以是代表你的浏览状态,你建立你的视图模型,并为您的暴露LiveData

data class FavouritesViewState(val favoriteStations: List<Station>, val favoritBuses: List<Bus>)

但是你知道取决于视图模型来构建最终的ViewState数据类有点打破单一责任原则,也让你依赖于Android框架。

我会使用具有工作站和总线用例的复合UseCase来处理它,并返回可从ViewModel轻松公开的组合数据。