2017-11-11 22 views
0

이것은 버그를 수정하는 것 이상의 아키텍처 문제입니다.클린 아키텍처 : 안드로이드에서 여러 개의 유스 케이스가있는 ViewModel

이 응용 프로그램에서 사용자가 버스 및/또는 버스 방송국을 즐겨 찾기로 표시 할 수 있다고 가정 해 봅니다. 내 질문은 두 UseCases 모두 ViewModel해야합니까 또는 현재 논리를 캡슐화하는 UseCase 빌드해야합니까?

또한 질문의 경우, 내가 UI 계층에 결합 된 데이터를 노출해야하는 방법은 어떤 의견을 환영합니다 사전에

감사 (favouritesExposedLiveData 참조) 완전히 확실하지 않다, 여기 내 ViewModel 당신이 추측 할 수 있어요 각 유스 케이스는 데이터 소스에서 올바른 데이터를 전달합니다.

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로부터 데이터를 바인딩하지 않습니다, 나는이 갈 올바른 방법입니다 확실하지 않다).

답변

0

ViewModel의 전체적인 점은보기가 사용하는 모델이라는 것입니다. 가능하면 가능한 한 가까이에 있어야합니다. 동일한보기 목록에있는 스테이션과 버스를 표시하지 않으면 (보기 흉한 것처럼 보입니다.) 그렇지 않으면 별도의보기가되며 별도의 모델을 가져야합니다.

+0

의견을 보내 주셔서 감사합니다. 질문에 답변하지 않으 셨습니다. 예, 버스와 역 (즐겨 찾기로 표시)을 모두 표시하려고합니다. –

0

이상적으로 ViewModel은보기에 대한보기 상태 만 갖고있는 것이 이상적입니다. MediatorLiveData를 사용하면 모든 상태 소스를 시간에 따라 뷰 상태를 나타내는 것으로 통합 할 수 있습니다.

당신이 가질 수있는 것은 당신이 최종의 ViewState를 구성하는 뷰 모델에 따라 알 그러나 당신이 당신의 노출 LiveData

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

를보기 모델을 구성하고 귀하의 ViewState를 나타내는 데이터 클래스 인 일종의 책임 원칙을 어기는 동시에 Android 프레임 워크에 종속되게 만듭니다.

스테이션 및 버스 사용 사례가 모두있는 복합 UseCase를 사용하여 접근하고 ViewModel에서 쉽게 노출 할 수있는 합성 된 데이터를 반환합니다.