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

Flux for Android

Flux for Android

This is the slide for DroidKaigi 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.

Shohei Kawano

February 04, 2018
Tweet

More Decks by Shohei Kawano

Other Decks in Technology

Transcript

  1. Action View Dispatcher Store Action Creator • User Interface •

    Render based on Store’s state • Store subscriber • Has no states
  2. Action View Dispatcher Store Action Creator • Helper • Creates

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

    by ActionCreator • Dispatched by Dispatcher • Delivered to Store
  4. Action View Dispatcher Store Action Creator • Central Hub for

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

    Changes its states and data only by receiving Actions • Has states / internal logic
  6. DRY

  7. 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) }
  8. 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) }
  9. <!—- 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}" … /> …
  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() { @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) }
  12. 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
  13. 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
  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) // Initialize View binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) }
  15. 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
  16. 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
  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) // Subscribe State loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } }
  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) // Subscribe State loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } }
  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) // initView() binding.fab.setOnClickListener { doSomething() } binding.userList.adapter = userListAdapter binding.userList.layoutManager = LinearLayoutManager(this) // subscribeState() loadingStore.loadingState.autoDisposable(scope) .subscribe { binding.isLoading = it } }
  20. 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() } …
  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) initView() subscribeState() } … View 3. Call ActionCreators’ functions
  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) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } …
  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) initView() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } … View
  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() subscribeState() // Create & Dispatch Action actionCreator.showUserList() } … Action View Dispatcher Store Action Creator
  25. 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
  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() // Create & Dispatch Action actionCreator.showUserList() } … Action Creator
  27. @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
  28. @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
  29. @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
  30. @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
  31. @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
  32. @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
  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)) }) } } LoadingAction Action
  34. 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)) }) } }
  35. Action sealed class LoadingAction(activity: Activity) { val activityKey: String =

    activity.componentName.className class Idle(activity: Activity) : LoadingAction(activity) class Loading(activity: Activity) : LoadingAction(activity) }
  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)) }) } } UserListAction Action
  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
  38. Action sealed class UserListAction { class ShowUserList(val userList: UserList) :

    UserListAction() class Error(val error: Throwable) : UserListAction() }
  39. Action sealed class UserListAction { class ShowUserList(val userList: UserList) :

    UserListAction() class Error(val error: Throwable) : UserListAction() } Action View Dispatcher Store Action Creator
  40. Action sealed class UserListAction { class ShowUserList(val userList: UserList) :

    UserListAction() class Error(val error: Throwable) : UserListAction() } Action View Dispatcher Store Action Creator
  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)) }) } } Action Creator
  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)) }) } } Dispatcher
  43. @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
  44. 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) }
  45. 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?
  46. 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
  47. 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
  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. @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
  50. @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
  51. @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
  52. @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
  53. @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
  54. @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
  55. @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
  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

    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
  59. @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
  60. @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
  61. @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
  62. @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
  63. @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
  64. @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
  65. 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 -> { … } } …
  66. 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 -> { … } } …
  67. @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
  68. 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 -> { … } } …
  69. 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 -> { … } } …
  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 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
  72. @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
  73. @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
  74. @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
  75. 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
  76. 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
  77. <!—- 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}" … /> …
  78. <!—- 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}" … /> …
  79. @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
  80. 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 -> { … } } …
  81. @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
  82. @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
  83. @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
  84. @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
  85. @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
  86. @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
  87. @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
  88. @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
  89. @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
  90. @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
  91. @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
  92. 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 } } } …
  93. 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 } } } …
  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 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
  96. @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
  97. @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
  98. @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
  99. 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
  100. 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
  101. 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
  102. 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
  103. 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 } } } …
  104. 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 } } } …
  105. DRY

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

    / Error Action 3. (Create & Dispatch Idle Action) Steps in ActionCreator Action Creator
  107. @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”.
  108. 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).
  109. 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
  110. 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