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

Flux for Android / Droidcon Boston 2018

Flux for Android / Droidcon Boston 2018

This is the slide for Droidcon Boston session "Flux: Utilize unidirectional data flow to think less and scale faster".

By utilizing a unidirectional data flow, we aim to think less and scale faster. Flux is all about having unidirectional data flow throughout the application using Flux components such as Action, Dispatcher, Store, and more.

While there are a lot of more benefits as well, declaring those components feature based rather than screen or view based, you may be able to make use of already-declared components and the logics, which helps you to make your app DRY, write less code than you otherwise have to write, and modify only once place when there needs a change in your logic or specification.

Below is a list of official Flux documentation links:

* facebook/flux: Application Architecture for Building User Interfaces
https://github.com/facebook/flux

* flux/examples/flux-concepts at master · facebook/flux
https://github.com/facebook/flux/tree/master/examples/flux-concepts#flux-parts

---

And below are the example implementations for Flux architecture and some slides:

* satorufujiwara/architecture-patterns-samples
https://github.com/satorufujiwara/architecture-patterns-samples

* ogaclejapan/FluxArchitectureSample: Sample app for Flux Architecture
https://github.com/ogaclejapan/FluxArchitectureSample

* Flux de Relax :) // Speaker Deck
https://speakerdeck.com/ogaclejapan/flux-de-relax

Shohei Kawano

March 27, 2018
Tweet

More Decks by Shohei Kawano

Other Decks in Programming

Transcript

  1. "

  2. Action View Dispatcher Store Action Creator • Render UI based

    on Store states/values • Store subscriber • Has no states
  3. Action View Dispatcher Store Action Creator • Helper • Creates

    Actions • Passes Actions to Dispatcher • Has no states
  4. Action View Dispatcher Store Action Creator • Container • Created

    by ActionCreator • Dispatched by Dispatcher • Delivered to Store
  5. Action View Dispatcher Store Action Creator • Central hub for

    all of the data flows • Dispatches Actions to Stores • Has no states
  6. Action View Dispatcher Store Action Creator • State manager •

    Changes its states and data only by receiving Actions • Has states / internal logic
  7. Action View Dispatcher Store Action Creator • State manager •

    Changes its states and data only by receiving Actions • Has states / internal logic
  8. •Not complicated diagram or boilerplates •You know where to look

    •Code consistency •Easy to test •Easy to debug •…
  9. DRY

  10. class UserListActivity : BaseActivity() { private val binding by lazy

    { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) }
  11. class UserListActivity : BaseActivity() { private val binding by lazy

    { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) }
  12. <!—- activity_user_list.xml —-> <?xml version="1.0" encoding="utf-8"?> <layout … > <data>

    <import type="android.view.View"/> <variable name="isLoading" type="boolean" /> </data> … <android.support.v7.widget.RecyclerView android:id=“@+id/user_list" … /> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{isLoading ? View.VISIBLE : View.GONE}" … /> …
  13. class UserListActivity : BaseActivity() { private val binding by lazy

    { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) }
  14. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) }
  15. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var userListStore: UserListStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } 1. Initialize View 2. Subscribe State 3. Call ActionCreator’s functions View 3 Steps in Activity / Fragment
  16. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var userListStore: UserListStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } 1. Initialize View View
  17. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) }
  18. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) }
  19. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) } View 2. Subscribe State
  20. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) } View 2. Subscribe “Loading” State
  21. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) // Subscribe State loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } }
  22. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) // Subscribe State loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } }
  23. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) // Subscribe State loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } }
  24. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // initView() binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) // subscribeState() loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } }
  25. class UserListActivity : Activity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() } …
  26. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() } … View 3. Call ActionCreators’ functions
  27. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } …
  28. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } … View
  29. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } … Action View Dispatcher Store Action Creator
  30. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } … Action View Dispatcher Store Action Creator
  31. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } … Action Creator
  32. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } … Action View Dispatcher Store Action Creator
  33. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action Creator Action View Dispatcher Store Action Creator
  34. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action Creator
  35. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action Creator
  36. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action Creator
  37. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action Creator
  38. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } LoadingAction Action
  39. Action @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private

    val api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } }
  40. Action sealed class LoadingAction(activity: Activity) { val activityKey: String =

    activity.componentName.className class Idle(activity: Activity) : LoadingAction(activity) class Loading(activity: Activity) : LoadingAction(activity) }
  41. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } UserListAction Action
  42. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action
  43. Action sealed class UserListAction { class ShowUserList(val userList: UserList) :

    UserListAction() class Error(val error: Throwable) : UserListAction() }
  44. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action Creator Action View Dispatcher Store Action Creator
  45. Action sealed class UserListAction { class ShowUserList(val userList: UserList) :

    UserListAction() class Error(val error: Throwable) : UserListAction() } Action View Dispatcher Store Action Creator
  46. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Action Creator
  47. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatcher
  48. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatcher
  49. Dispatcher class Dispatcher { private val eventBus = EventBus.builder() .addIndex(DispatcherIndex())

    .throwSubscriberException(BuildConfig.DEBUG) .build() fun dispatch(event: Any) { eventBus.post(event) } fun register(observer: Any) { eventBus.register(observer) } fun unregister(observer: Any) { eventBus.unregister(observer) }
  50. class Dispatcher { private val eventBus = EventBus.builder() .addIndex(DispatcherIndex()) .throwSubscriberException(BuildConfig.DEBUG)

    .build() fun dispatch(event: Any) { eventBus.post(event) } fun register(observer: Any) { eventBus.register(observer) } fun unregister(observer: Any) { eventBus.unregister(observer) } Dispatcher For Broadcasting Actions: • RxJava • EventBus … and more?
  51. Action sealed class UserListAction { class ShowUserList(val userList: UserList) :

    UserListAction() class Error(val error: Throwable) : UserListAction() } Action View Dispatcher Store Action Creator
  52. Dispatcher class Dispatcher { private val eventBus = EventBus.builder() .addIndex(DispatcherIndex())

    .throwSubscriberException(BuildConfig.DEBUG) .build() fun dispatch(event: Any) { eventBus.post(event) } fun register(observer: Any) { eventBus.register(observer) } fun unregister(observer: Any) { eventBus.unregister(observer) } Action View Dispatcher Store Action Creator
  53. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatcher
  54. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatch LoadingAction Dispatcher
  55. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatcher
  56. @PerActivity class LoadingStore @Inject constructor(private val activityKey: String, dispatcher: Dispatcher,

    navi: NaviComponent) { private val loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { … } Store
  57. @PerActivity class LoadingStore @Inject constructor(private val activityKey: String, dispatcher: Dispatcher,

    navi: NaviComponent) { private val loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { … } Store
  58. @PerActivity class LoadingStore @Inject constructor(private val activityKey: String, dispatcher: Dispatcher,

    navi: NaviComponent) { private val loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { … } Store
  59. @PerActivity class LoadingStore @Inject constructor(private val activityKey: String, dispatcher: Dispatcher,

    navi: NaviComponent) { private val loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { … } Store For Observing Lifecycle Events: • AAC: Lifecycle • RxLifecycle: Navi … and more? Store
  60. @PerActivity class LoadingStore @Inject constructor(private val activityKey: String, dispatcher: Dispatcher,

    navi: NaviComponent) { private val loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { … } Store
  61. @PerActivity class LoadingStore @Inject constructor(private val activityKey: String, dispatcher: Dispatcher,

    navi: NaviComponent) { private val loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { … } Store
  62. @PerActivity class LoadingStore @Inject constructor(private val activityKey: String, dispatcher: Dispatcher,

    navi: NaviComponent) { private val loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { … } Store
  63. @PerActivity class LoadingStore @Inject constructor( … ) { private val

    loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { … } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { if (action.activityKey == activityKey) { when (action) { is LoadingAction.Loading -> { loadingSubject.onNext(true) } is LoadingAction.Idle -> { loadingSubject.onNext(false) } … Store
  64. @PerActivity class LoadingStore @Inject constructor( … ) { private val

    loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { … } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { if (action.activityKey == activityKey) { when (action) { is LoadingAction.Loading -> { loadingSubject.onNext(true) } is LoadingAction.Idle -> { loadingSubject.onNext(false) } … Store
  65. @PerActivity class LoadingStore @Inject constructor( … ) { private val

    loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { … } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { if (action.activityKey == activityKey) { when (action) { is LoadingAction.Loading -> { loadingSubject.onNext(true) } is LoadingAction.Idle -> { loadingSubject.onNext(false) } … Store
  66. @PerActivity class LoadingStore @Inject constructor( … ) { private val

    loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { … } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { if (action.activityKey == activityKey) { when (action) { is LoadingAction.Loading -> { loadingSubject.onNext(true) } is LoadingAction.Idle -> { loadingSubject.onNext(false) } … Store
  67. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatch UserListAction Dispatcher
  68. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatcher
  69. @PerActivity class UserListActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi, private val activity: Activity) { fun showUserList() { dispatcher.dispatch(LoadingAction.Loading(activity)) api.fetchUserList().subscribeBy( onSuccess= { userList -> dispatcher.dispatch(UserListAction.ShowUserList(userList)) dispatcher.dispatch(LoadingAction.Idle(activity)) }, onError = { e -> dispatcher.dispatch(UserListAction.Error(e)) dispatcher.dispatch(LoadingAction.Idle(activity)) }) } } Dispatcher
  70. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { userList.addAll(action.userList.data) } is UserListAction.Error -> { … } } …
  71. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { userList.addAll(action.userList.data) } is UserListAction.Error -> { … } } …
  72. @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) { private

    val userList = ObservableArrayList<User>() … fun addOnListChangedCallback(callback: ObservableList.OnListChangedCallback<ObservableList<User>>) { userList.addOnListChangedCallback(callback) } fun removeOnListChangedCallback(callback: ObservableList.OnListChangedCallback<ObservableList<User>>) { userList.removeOnListChangedCallback(callback) } Store
  73. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { userList.addAll(action.userList.data) } is UserListAction.Error -> { … } } …
  74. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { userList.addAll(action.userList.data) } is UserListAction.Error -> { … } } …
  75. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { userList.addAll(action.userList.data) } is UserListAction.Error -> { … } } …
  76. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val listSubject = PublishSubject.create<List<User>>() val listState: Observable<List<User>> = listSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { listSubject.onNext(action.userList.data) } } } } Action View Dispatcher Store Action Creator
  77. @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) { private

    val listSubject = PublishSubject.create<List<User>>() val listState: Observable<List<User>> = listSubject.hide() init { Streaming Loading State Change Using RxJava Store
  78. @PerActivity class LoadingStore @Inject constructor( … ) { private val

    loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { … } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { if (action.activityKey == activityKey) { when (action) { is LoadingAction.Loading -> { loadingSubject.onNext(true) } is LoadingAction.Idle -> { loadingSubject.onNext(false) } … Store
  79. @PerActivity class LoadingStore @Inject constructor( … ) { private val

    loadingSubject = PublishSubject.create<Boolean>() val loadingState: Observable<Boolean> = loadingSubject.hide() init { … } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { if (action.activityKey == activityKey) { when (action) { is LoadingAction.Loading -> { loadingSubject.onNext(true) } is LoadingAction.Idle -> { loadingSubject.onNext(false) } … Store
  80. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // initView() binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) // subscribeState() loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } } View
  81. class UserListActivity : BaseActivity() { @Inject lateinit var actionCreator: UserListActionCreator

    @Inject lateinit var loadingStore: LoadingStore @Inject lateinit var userListAdapter: UserListAdapter private val binding by lazy { DataBindingUtil.setContentView<ActivityUserListBinding>( this, R.layout.activity_user_list) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // initView() binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) // subscribeState() loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } } View
  82. <!—- activity_user_list.xml —-> <?xml version="1.0" encoding="utf-8"?> <layout … > <data>

    <import type="android.view.View"/> <variable name="isLoading" type="boolean" /> </data> … <android.support.v7.widget.RecyclerView android:id=“@+id/user_list" … /> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{isLoading ? View.VISIBLE : View.GONE}" … /> …
  83. <!—- activity_user_list.xml —-> <?xml version="1.0" encoding="utf-8"?> <layout … > <data>

    <import type="android.view.View"/> <variable name="isLoading" type="boolean" /> </data> … <android.support.v7.widget.RecyclerView android:id=“@+id/user_list" … /> <ProgressBar android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="@{isLoading ? View.VISIBLE : View.GONE}" … /> …
  84. @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) { private

    val listSubject = PublishSubject.create<List<User>>() val listState: Observable<List<User>> = listSubject.hide() init { Streaming UserList Change Using Data Binding Store
  85. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { userList.addAll(action.userList.data) } is UserListAction.Error -> { … } } …
  86. @PerActivity class UserListAdapter @Inject constructor( private val store: UserListStore, navi:

    NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { private val listChangeCallback = … init { navi.addListener(Event.CREATE, { store.addOnListChangedCallback(listChangeCallback) }) navi.addListener(Event.DESTROY, { store.removeOnListChangedCallback(listChangeCallback) }) } … View
  87. @PerActivity class UserListAdapter @Inject constructor( private val store: UserListStore, navi:

    NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { private val listChangeCallback = … init { navi.addListener(Event.CREATE, { store.addOnListChangedCallback(listChangeCallback) }) navi.addListener(Event.DESTROY, { store.removeOnListChangedCallback(listChangeCallback) }) } … View
  88. @PerActivity class UserListAdapter @Inject constructor( private val store: UserListStore, navi:

    NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { private val listChangeCallback = … init { navi.addListener(Event.CREATE, { store.addOnListChangedCallback(listChangeCallback) }) navi.addListener(Event.DESTROY, { store.removeOnListChangedCallback(listChangeCallback) }) } … View
  89. @PerActivity class UserListAdapter @Inject constructor( private val store: UserListStore navi:

    NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { private val listChangeCallback = … init { … } override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.binding.executePendingBindings() } override fun getItemCount() = store.userListSize … View
  90. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val listSubject = PublishSubject.create<List<User>>() val listState: Observable<List<User>> = listSubject.hide() init { navi.addListener(Event.CREATE, { dispatcher.register(this)}) navi.addListener(Event.DESTROY, { dispatcher.unregister(this)}) } @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserListAction) { when (action) { is UserListAction.ShowUserList -> { listSubject.onNext(action.userList.data) } } } } Action View Dispatcher Store Action Creator
  91. @PerActivity class UserListAdapter @Inject constructor( private val store: UserListStore, navi:

    NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { init { … } override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.binding.executePendingBindings() } … View
  92. @PerActivity class UserListAdapter @Inject constructor( private val userActionCreator: UserActionCreator, private

    val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { init { … } override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.executePendingBindings() } … View
  93. @PerActivity class UserListAdapter @Inject constructor( private val userActionCreator: UserActionCreator, private

    val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { init { … } override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.executePendingBindings() } … View
  94. @PerActivity class UserListAdapter @Inject constructor( private val userActionCreator: UserActionCreator, private

    val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { init { … } override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.executePendingBindings() } … View
  95. @PerActivity class UserListAdapter @Inject constructor( private val userActionCreator: UserActionCreator, private

    val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { init { … } override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.executePendingBindings() } … View
  96. @PerActivity class UserActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi) { fun favorite(user: User) { api.favorite(user.id).subscribeBy( onComplete = { dispatcher.dispatch(UserAction.Favorite(user.id)) }, … } } Action Creator
  97. @PerActivity class UserActionCreator @Inject constructor(private val dispatcher: Dispatcher, private val

    api: SomeApi) { fun favorite(user: User) { api.favorite(user.id).subscribeBy( onComplete = { dispatcher.dispatch(UserAction.Favorite(user.id)) }, … } } Action Creator
  98. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { … } … @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserAction) { when (action) { is UserAction.Favorite -> { userList.find { it.id == action.targetUserId }?.let { // Update or replace with new user } } } …
  99. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { … } … @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserAction) { when (action) { is UserAction.Favorite -> { userList.find { it.id == action.targetUserId }?.let { // Update or replace with new user } } } …
  100. @PerActivity class UserListAdapter @Inject constructor( private val userActionCreator: UserActionCreator, private

    val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { init { … } override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.executePendingBindings() } … View
  101. @PerActivity class UserListAdapter @Inject constructor( private val activityActionCreator: ActivityActionCreator, private

    val userActionCreator: UserActionCreator, private val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { … override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.root.setOnClickListener { activityActionCreator.startUserDetailActivity(user) } holder.binding.executePendingBindings() } … View
  102. @PerActivity class UserListAdapter @Inject constructor( private val activityActionCreator: ActivityActionCreator, private

    val userActionCreator: UserActionCreator, private val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { … override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.root.setOnClickListener { activityActionCreator.startUserDetailActivity(user) } holder.binding.executePendingBindings() } … View
  103. @PerActivity class UserListAdapter @Inject constructor( private val activityActionCreator: ActivityActionCreator, private

    val userActionCreator: UserActionCreator, private val store: UserListStore, navi: NaviComponent): RecyclerView.Adapter<RecyclerView.ViewHolder>() { … override fun onBindViewHolder( … ) { … holder.binding.user = store.getUserAt(position) holder.favIcon.setOnClickListener { userActionCreator.favorite(user) } holder.binding.root.setOnClickListener { activityActionCreator.startUserDetailActivity(user) } holder.binding.executePendingBindings() } … View
  104. @PerActivity class ActivityActionCreator @Inject constructor(private val activity: Activity) { fun

    startUserDetailActivity(user: User) { val intent = UserDetailActivity.createIntent(activity, user) activity.startActivity(intent) } fun start…Activity ( … ) { … } fun start…Activity ( … ) { … } } Action Creator
  105. class UserDetailActivity : BaseActivity() { @Inject lateinit var actionCreator: UserActionCreator

    @Inject lateinit var loadingStore: LoadingStore private val binding by lazy { DataBindingUtil.setContentView<ActivityUserDetailBinding>( this, R.layout.activity_user_detail) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() } … View
  106. class UserDetailActivity : BaseActivity() { @Inject lateinit var actionCreator: UserActionCreator

    @Inject lateinit var loadingStore: LoadingStore private val binding by lazy { DataBindingUtil.setContentView<ActivityUserDetailBinding>( this, R.layout.activity_user_detail) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) initView() subscribeState() } … View
  107. class UserDetailActivity : BaseActivity() { @Inject lateinit var actionCreator: UserActionCreator

    @Inject lateinit var loadingStore: LoadingStore private val binding by lazy { DataBindingUtil.setContentView<ActivityUserDetailBinding>( this, R.layout.activity_user_detail) } override fun onCreate(savedInstanceState: Bundle?) { initView() … } private fun initView() { binding.fab.setOnClickListener { userActionCreator.favorite(user) } } … View
  108. class UserDetailActivity : BaseActivity() { @Inject lateinit var actionCreator: UserActionCreator

    @Inject lateinit var loadingStore: LoadingStore private val binding by lazy { DataBindingUtil.setContentView<ActivityUserDetailBinding>( this, R.layout.activity_user_detail) } override fun onCreate(savedInstanceState: Bundle?) { initView() … } private fun initView() { binding.fab.setOnClickListener { userActionCreator.favorite(user) } } … View
  109. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { … } … @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserAction) { when (action) { is UserAction.Favorite -> { userList.find { it.id == action.targetUserId }?.let { // Update or replace with new user } } } …
  110. Store @PerActivity class UserListStore @Inject constructor(dispatcher: Dispatcher, navi: NaviComponent) {

    private val userList = ObservableArrayList<User>() init { … } … @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserAction) { when (action) { is UserAction.Favorite -> { userList.find { it.id == action.targetUserId }?.let { // Update or replace with new user } } } …
  111. DRY

  112. 1. (Create & Dispatch LoadingAction) 2. Create & Dispatch Success

    / Error Action 3. (Create & Dispatch Idle Action) Steps in ActionCreator Action Creator
  113. @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: LoadingAction) { if (action.activityKey ==

    activityKey) { when (action) { is LoadingAction.Loading -> { loadingSubject.onNext(true) } is LoadingAction.Idle -> { loadingSubject.onNext(false) } … Store When given action is Loading, then the next loading state is “true”, if the action is Idle, then “false”.
  114. Store @Subscribe(threadMode = ThreadMode.MAIN) fun on(action: UserAction) { when (action)

    { is UserAction.Favorite -> { userList.find { it.id == action.targetUserId }?.let { // Update or replace with new user } } } … When given action is User’s Favorite Action, then find target user from user list and update as favorited (if there is).
  115. Dispatcher class Dispatcher { private val eventBus = EventBus.builder() .addIndex(DispatcherIndex())

    .throwSubscriberException(BuildConfig.DEBUG) .build() fun dispatch(event: Any) { eventBus.post(event) } fun register(observer: Any) { eventBus.register(observer) } fun unregister(observer: Any) { eventBus.unregister(observer) } Action View Dispatcher Store Action Creator
  116. Dispatcher class Dispatcher { private val eventBus = EventBus.builder() .addIndex(DispatcherIndex())

    .throwSubscriberException(BuildConfig.DEBUG) .build() fun dispatch(event: Any) { eventBus.post(event) } fun register(observer: Any) { eventBus.register(observer) } fun unregister(observer: Any) { eventBus.unregister(observer) } Action View Dispatcher Store Action Creator
  117. •Flux is for utilizing unidirectional data flow by declaring the

    components •Store is the only state manager •Makes your code DRY and consistent with minimal boilerplates Flux Summary