干净的体系结构:在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))
}
}
}
注:目前MediatorLiveData
(favouritesMediatorLiveData
)没有在这个时候数据绑定回favouritesExposedLiveData
,因为,我不知道这是要走正确的方式)。
ViewModel的重点在于它是视图使用的模型。它应该尽可能接近。除非你在同一个视图列表中显示车站和公共汽车(否则),否则,它们是单独的视图,应该有不同的模型。
理想情况下,一个ViewModel只能有其视图的视图状态。通过使用MediatorLiveData,您可以将所有状态来源聚合为代表随时间变化的视图状态。
什么你可以是代表你的浏览状态,你建立你的视图模型,并为您的暴露LiveData
data class FavouritesViewState(val favoriteStations: List<Station>, val favoritBuses: List<Bus>)
但是你知道取决于视图模型来构建最终的ViewState数据类有点打破单一责任原则,也让你依赖于Android框架。
我会使用具有工作站和总线用例的复合UseCase来处理它,并返回可从ViewModel轻松公开的组合数据。
感谢您的反馈,但您并未真正回答这个问题,是的,我想同时显示巴士和车站(标记为收藏夹)。 –