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

Redux for Android

Redux for Android

It may be an unpopular opinion, but I recently found an amazing architectural pattern from the Javascript world. Ok, ok, before you go let me ask you this… do you like code that is easier to debug? How about a single source of truth and more deterministic code paths? Still with me? Let’s talk about Redux and how Redux can help simplify your architecture and your life. Worried that you won’t be able to use any of the nice lifecycle aware libraries Google created for us? Redux still works with Android Architecture components so we will also look at how we can utilize Live Data and View Models as well as other popular libraries and technologies.

9904145db476b6658d75fff27b1929ed?s=128

Elliott Chenger

August 26, 2019
Tweet

Transcript

  1. Redux for Android Elliott Chenger sli.do#3073

  2. Don’t Redux because it‘s the “cool” thing to do @echenger

    sli.do#3073
  3. “It Depends” Is The Answer To Your Android Question -

    Sam Edwards MVWTF: Demystifying Architecture Patterns - Adam McNeilly @echenger sli.do#3073
  4. Why did we choose Redux? @echenger sli.do#3073

  5. Architectural Goals @echenger sli.do#3073

  6. Clear Responsibility @echenger sli.do#3073

  7. Testability @echenger sli.do#3073

  8. Easy to Debug @echenger sli.do#3073

  9. State Management @echenger sli.do#3073

  10. User’s State @echenger sli.do#3073

  11. @echenger sli.do#3073

  12. @echenger sli.do#3073

  13. @echenger sli.do#3073

  14. What are possible solutions? @echenger sli.do#3073

  15. Modern Architectures M V C M V P M V

    I M V V M @echenger sli.do#3073
  16. MVP Model View Presenter @echenger sli.do#3073

  17. MVP Presenter Model View State @echenger sli.do#3073

  18. MVP @echenger sli.do#3073

  19. MVP @echenger sli.do#3073

  20. Redux @echenger sli.do#3073

  21. Redux @echenger Presentation Layer Store State sli.do#3073

  22. Centralized State @echenger sli.do#3073

  23. Presentation Layer Store State @echenger sli.do#3073

  24. Presentation Layer Store State Login Feed Inbox Profile List Detail

    @echenger sli.do#3073
  25. Unidirectional Data Flow @echenger sli.do#3073

  26. Presentation Layer Store State Login Feed Inbox Profile List Detail

    dispatch() onStateChanged() @echenger sli.do#3073
  27. Redux Terminology @echenger sli.do#3073

  28. Presentation Layer Store State @echenger sli.do#3073

  29. Presentation Layer Store State Middleware Reducer Dispatch an Action Subscribe


    to changes @echenger sli.do#3073
  30. App State @echenger sli.do#3073

  31. What the state represents not how it is displayed @echenger

    sli.do#3073
  32. @echenger sli.do#3073

  33. @echenger sli.do#3073

  34. data class AppState(val firstName: String, val lastName: String, val phoneNumber:

    String) @echenger sli.do#3073
  35. Actions @echenger sli.do#3073

  36. val searchAction = SetSearchText(searchTerm) store.dispatch(searchAction) @echenger sli.do#3073

  37. data class SetSearchText(val searchTerm: String) : Action @echenger sli.do#3073

  38. object ExecuteSearch : Action @echenger sli.do#3073

  39. Reducers @echenger sli.do#3073

  40. Update State @echenger sli.do#3073

  41. override fun reduce(state: AppState, action: Action?): AppState { } @echenger

    sli.do#3073
  42. override fun reduce(state: AppState, action: Action?): AppState { return when

    (action) { is SetSearchText -> { return state.copy(searchTerm = searchTerm) } else -> state } } @echenger sli.do#3073
  43. return state.copy(searchTerm = searchTerm) @echenger sli.do#3073

  44. Inverted Reducer @echenger sli.do#3073

  45. override fun reduce(state: AppState, action: Action?): AppState { return when

    (action) { is SetSearchText -> { return state.copy(searchTerm = searchTerm) } is ExecuteSearch -> { return state.copy(isLoading = true) } is ImageSearchResponseAction -> { return state.copy( isLoading = false, imageCollection = imageCollection ) } else -> state } } @echenger sli.do#3073
  46. interface Reducible { fun reduce(state: AppState): AppState } @echenger sli.do#3073

  47. override fun reduce(state: AppState, action: Action?): AppState { return when

    (action) { is Reducible -> { action.reduce(state) } else -> state } } @echenger sli.do#3073
  48. data class SetSearchText(val searchTerm: String) : ListAction(), Reducible { override

    fun reduce(state: AppState): AppState { return state.copy(searchTerm = searchTerm) } } class ExecuteSearch : ListAction(), Reducible { override fun reduce(state: AppState): AppState { return state.copy(isLoading = true) } } data class ImageSearchResponseAction(val imageCollection: ImageCollection) : ListAction(), Reducible { override fun reduce(state: AppState): AppState { return state.copy( isLoading = false, imageCollection = imageCollection ) } } @echenger sli.do#3073
  49. Presentation Layer @echenger sli.do#3073

  50. Presentation Layer Store State Middleware Reducer @echenger sli.do#3073

  51. Presentation Layer Store State Middleware Reducer @echenger sli.do#3073

  52. Presentation Layer Store Creates View Displayed UI Model @echenger sli.do#3073

  53. ViewModel Store State Middleware Reducer Activity/Fragment LiveData State UI Model

    @echenger sli.do#3073
  54. class ListViewModel(application: Application) : AndroidViewModel(application), StoreSubscriber<AppState> { val uiModelLiveData =

    MutableLiveData<MainUiModel>() private val store: StoreType<AppState> = (application as App).store init { store.subscribe(this) } fun onSearch(searchTerm: String) { val searchAction = SetSearchText(searchTerm) store.dispatch(searchAction) } override fun newState(state: AppState) { val state = store.state uiModelLiveData.value = MainUiModel.fromListState(state.listState) } override fun onCleared() { store.unsubscribe(this) } } @echenger sli.do#3073
  55. init { store.subscribe(this) } @echenger sli.do#3073

  56. override fun newState(state: AppState) { val state = store.state uiModelLiveData.value

    = MainUiModel.fromListState(state.listState) } @echenger sli.do#3073
  57. Middleware @echenger sli.do#3073

  58. Presentation Layer Store State Middleware Reducer @echenger sli.do#3073

  59. class LoggingMiddleware : Middleware<AppState> { override fun dispatch(store: Store<AppState>, next:

    Dispatcher, action: Action): Action { Log.d("APP", "Dispatching $action") Log.d("APP", "SearchTeam before reducer ${store.state.listState.searchTerm}") val nextAction = next.dispatch(action) Log.d("APP", "SearchTeam after reducer ${store.state.listState.searchTerm}") return nextAction } } @echenger sli.do#3073
  60. What is next()? @echenger sli.do#3073

  61. Presentation Layer Store State Middleware Reducer @echenger sli.do#3073

  62. Store State Reducer @echenger sli.do#3073

  63. Store C A Reducer B next() next() next() @echenger sli.do#3073

  64. Async Middleware @echenger sli.do#3073

  65. Store State Middleware Reducer isLoading = true @echenger sli.do#3073 This

    slide won’t make sense until the talk video is up because it has lots of animations!
  66. Store State Middleware Reducer isLoading = false
 response = data

    isLoading = true @echenger sli.do#3073
  67. Wrap Up @echenger sli.do#3073

  68. • Clear responsibility • Testability • Easier Debug-ability • State

    Management Redux @echenger sli.do#3073
  69. Q&A @echenger sli.do#3073 http://bit.ly/3429SiQ