Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Use MVI Architecture in Kotlin × Android

itome
November 15, 2018

Use MVI Architecture in Kotlin × Android

itome

November 15, 2018
Tweet

More Decks by itome

Other Decks in Technology

Transcript

  1. MVI Architectureͱ͸ʁ 1min ୯ํ޲σʔλϑϩʔ • Model • View • Intent(≠android.content.Intent)

    ViewModelͰ Intent → Action → Result → Result ͱσʔλΛม׵͍ͯ͘͜͠ͱͰ ঢ়ଶΛมߋ͢Δ
  2. RxʹΑΔ࣮૷ྫ 2min sealed class EventsIntent : MviIntent { object FetchFirstPageIntent

    : EventsIntent() data class FetchPageIntent(val pageNum: Int) : EventsIntent() object FetchLoginUserIntent : EventsIntent() } sealed class EventsAction : MviAction { object FetchFirstPageAction : EventsAction() data class FetchEventsPageAction( val pageNum: Int ) : EventsAction() object FetchLoginUserAction : EventsAction() }
  3. RxʹΑΔ࣮૷ྫ 2min private fun actionFromIntent(intent: EventsIntent): EventsAction { return when

    (intent) { FetchFirstPageIntent -> FetchFirstPageAction is FetchPageIntent -> FetchEventsPageAction(intent.pageNum) FetchLoginUserIntent -> FetchLoginUserAction } }
  4. RxʹΑΔ࣮૷ྫ 2min sealed class EventsResult : MviResult { sealed class

    FetchFirstPageResult : EventsResult() { data class Success(val events: List<Event>) : FetchFirstPageResult() data class Failure(val error: Throwable) : FetchFirstPageResult() object InFlight : FetchFirstPageResult() } sealed class FetchEventsPageResult : EventsResult() { data class Success(val events: List<Event>) : FetchEventsPageResult() data class Failure(val error: Throwable) : FetchEventsPageResult() object InFlight : FetchEventsPageResult() } sealed class FetchLoginUserResult : EventsResult() { data class Success(val user: User) : FetchLoginUserResult() data class Failure(val error: Throwable) : FetchLoginUserResult() object InFlight : FetchLoginUserResult() } }
  5. RxʹΑΔ࣮૷ྫ 2min override val actionProcessor = mergeProcessor( fetchFirstPageProcessor to FetchFirstPageAction::class,

    fetchEventsPageProcessor to FetchEventsPageAction::class, fetchLoginUserProcessor to FetchLoginUserAction::class ) private val fetchFirstPageProcessor = createProcessor<FetchFirstPageAction, FetchFirstPageResult> { repository.getEvents(1) .toObservable() .map { user -> FetchFirstPageResult.Success(user) } .cast(FetchFirstPageResult::class.java) .onErrorReturn(FetchFirstPageResult::Failure) .subscribeOn(schedulerProvider.io()) .observeOn(schedulerProvider.ui()) .startWith(FetchFirstPageResult.InFlight) }
  6. RxʹΑΔ࣮૷ྫ 2min data class EventsViewState( val loginUser: User?, val events:

    List<Event>, val error: Throwable?, val nextPage: Int, val isLoading: Boolean ) : MviViewState { companion object { fun idle(): EventsViewState { return EventsViewState( loginUser = null, events = emptyList(), error = null, nextPage = 1, isLoading = false ) } } }
  7. RxʹΑΔ࣮૷ྫ 2min private val reducer = { previousState: EventsViewState, result:

    EventsResult -> when (result) { is FetchFirstPageResult -> when (result) { is FetchFirstPageResult.Success -> previousState.copy( events = result.events, error = null, isLoading = false, nextPage = 2 ) is FetchFirstPageResult.Failure -> previousState.copy(error = result.error, isLoading = false) FetchFirstPageResult.InFlight -> previousState.copy(isLoading = true) }
  8. RxʹΑΔ࣮૷ྫ 2min private fun compose(): Observable<EventsViewState> { return intentsSubject .map(this::actionFromIntent)

    .compose(actionProcessorHolder.actionProcessor) .scan(EventsViewState.idle(), reducer) .replay(1) .autoConnect(0) }