清洁架构:Android上具有多个UseCase的ViewModel

时间:2017-11-11 11:57:50

标签: android mvvm architecture kotlin viewmodel

这更像是一个架构问题,而不是修复它的错误。

我们假设此应用程序允许用户将总线和/或总线站标记为收藏夹。我的问题是,我应该使用两个UseCases ViewModel还是应该构建一个封装当前逻辑的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,因为此时我不确定这个是正确的方法;)。

2 个答案:

答案 0 :(得分:1)

理想情况下,ViewModel只能为其视图提供视图状态。通过使用MediatorLiveData,您可以将所有状态源聚合为一个表示视图状态的状态源。

您可以拥有的是一个数据类,它代表您在视图模型上构建的ViewState,并且是您公开的LiveData

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

但是你知道依赖于ViewModel来构造最终的ViewState,这有点打破了单一责任原则,也让你依赖于Android框架。

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

答案 1 :(得分:0)

ViewModel的重点在于它是视图所使用的模型。它应该尽可能接近。除非你在相同的视图列表中显示站点和总线(看起来很难看),否则,它们是单独的视图,并且应该得到单独的模型。