Slide 1

Slide 1 text

 Koin×AndroidͰMVI ΞʔΩςΫνϟΛ࠾༻͢Δ #potatetips #56

Slide 2

Slide 2 text

ࣗݾ঺հ 0min

Slide 3

Slide 3 text

ࣗݾ঺հ 0min ௩ຊ෢ࢤ ! https://twitter.com/itometeam " https://github.com/itome # https://medium.com/@itometeam cyberagent/cats

Slide 4

Slide 4 text

MVI Architectureͱ͸ʁ 1min

Slide 5

Slide 5 text

MVI Architectureͱ͸ʁ 1min ୯ํ޲σʔλϑϩʔ • Model • View • Intent(≠android.content.Intent) ViewModelͰ Intent → Action → Result → Result ͱσʔλΛม׵͍ͯ͘͜͠ͱͰ ঢ়ଶΛมߋ͢Δ

Slide 6

Slide 6 text

RxʹΑΔ࣮૷ྫ 2min

Slide 7

Slide 7 text

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() }

Slide 8

Slide 8 text

RxʹΑΔ࣮૷ྫ 2min private fun actionFromIntent(intent: EventsIntent): EventsAction { return when (intent) { FetchFirstPageIntent -> FetchFirstPageAction is FetchPageIntent -> FetchEventsPageAction(intent.pageNum) FetchLoginUserIntent -> FetchLoginUserAction } }

Slide 9

Slide 9 text

RxʹΑΔ࣮૷ྫ 2min sealed class EventsResult : MviResult { sealed class FetchFirstPageResult : EventsResult() { data class Success(val events: List) : FetchFirstPageResult() data class Failure(val error: Throwable) : FetchFirstPageResult() object InFlight : FetchFirstPageResult() } sealed class FetchEventsPageResult : EventsResult() { data class Success(val events: List) : 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() } }

Slide 10

Slide 10 text

RxʹΑΔ࣮૷ྫ 2min override val actionProcessor = mergeProcessor( fetchFirstPageProcessor to FetchFirstPageAction::class, fetchEventsPageProcessor to FetchEventsPageAction::class, fetchLoginUserProcessor to FetchLoginUserAction::class ) private val fetchFirstPageProcessor = createProcessor { 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) }

Slide 11

Slide 11 text

RxʹΑΔ࣮૷ྫ 2min data class EventsViewState( val loginUser: User?, val events: List, 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 ) } } }

Slide 12

Slide 12 text

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) }

Slide 13

Slide 13 text

RxʹΑΔ࣮૷ྫ 2min private fun compose(): Observable { return intentsSubject .map(this::actionFromIntent) .compose(actionProcessorHolder.actionProcessor) .scan(EventsViewState.idle(), reducer) .replay(1) .autoConnect(0) }

Slide 14

Slide 14 text

RxʹΑΔ࣮૷ྫ 2min ιʔείʔυ͸ https://github.com/itome/GithubMVI

Slide 15

Slide 15 text

ϝϦοτ / σϝϦοτ 2min

Slide 16

Slide 16 text

ϝϦοτ 2min ϓϩάϥϚʔʹର͢Δ੍໿͕ڧ͍ ςετ͕༰қ ɾਓʹΑ࣮ͬͯ૷͕มΘΔ෦෼ΛͰ͖Δ͚ͩ཈͑ΒΕΔ ɾ֤ॲཧͰೖྗͱग़ྗ͕ඞͣ̍ΧॴʹͳΔͨΊɺ ɹςετ͢΂͖͜ͱ͕໌֬ ΤϥʔϋϯυϦϯά͕༰қ ɾViewͷΠϕϯτ͔ΒViewͷߋ৽·Ͱ͕ҰຊͷετϦʔϜʹ ɹͳ͍ͬͯΔͨΊɺྫ֎ॲཧ͕Θ͔Γ΍͍͢

Slide 17

Slide 17 text

σϝϦοτ 2min ̍ճ͖ΓͷΠϕϯτΛ఻͑Δͷ͕೉͍͠ ෳࡶͳϨΠΞ΢τͰ͸ViewStateͷߋ৽ͷॲཧ͕ॏ͘ͳΔ ɾViewModelͷग़ྗ͕ViewStateͷΈͰ͋ΔͨΊɺҰճ͖ΓͷΠϕϯτΛ ɹViewModelଆ͔Βى͍ͨ࣌͜͠͸ɺflagΛ࣋ͨͤΔͳͲͷ޻෉͕ඞཁ ɾAndroidʹ͸Reactͷࠩ෼ߋ৽ͷΑ͏ͳ࢓૊Έ͕ଘࡏ͠ͳ͍ͨΊɺ ɹViewStateͷҰ෦Λߋ৽͚ͨͩ͠ͰɺViewStateʹؔ࿈͢Δ ɹશͯͷView͕ߋ৽͞Εͯ͠·͏ ৑௕ʹͳΓ΍͍͢ ɾίʔυͷϘΠϥʔϓϨʔτ͕ଟ͍ͨΊɺখ͞ͳॲཧͰ΋͔ͳΓͷ ɹίʔυΛॻ͘ඞཁ͕͋Δɻ

Slide 18

Slide 18 text

·ͱΊ 0.5min

Slide 19

Slide 19 text

͋Γ͕ͱ͏͍͟͝·ͨ͠ ! https://twitter.com/itometeam " https://github.com/itome # https://medium.com/@itometeam Takeshi Tsukamoto cyberagent/cats