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

Data Uni-Directional Architecture (UDA) in Android

Data Uni-Directional Architecture (UDA) in Android

2018년 11월 10일 GDG DevFest Seoul 2018, 11월 17일 Incheon 에서 발표한 내용입니다. Data Uni-Directional Architecture를 안드로이드에 적용한 Flux, Redux, MVI 3가지 예시를 통해 설명하였습니다.

Seungmin 마량

November 10, 2018
Tweet

More Decks by Seungmin 마량

Other Decks in Technology

Transcript

  1. ݾର 1. ࣁ࣌ ݾ಴ 2. അ ҳઑ੄ ޙઁ੼ 3. Data

    Uni-Directional Architecture (UDA) 4. Flux 5. Redux 6. MVI 7. UDA ੿ܻ 8. рױ ਽ਊ 9. ݃ޖܻ Korea
  2. ੉ߣ ࣁ࣌ਸ ా೧ ৈ۞ٜ࠙੉ ঳যщਵݶ જѷח Ѫ ࣁ࣌ ݾ಴ 1.UDAۆ

    Ѫ੉ ੓ҳա 2.੷۠ ੉ਬীࢲ UDA ۄח Ѫ੉ ա৳ҳա 3.UDAח ӝઓ ইఃఫ୛৬ ੷۠ ର੉੼੉ ੓ҳա 4.਋ܻ জ਷ UDAо ೙ਃೡө? 5.ӝઓ ҳઑ۽ ૞ৈ૓ ਋ܻ জী UDAܳ যڌѱ ੸ਊೡө? (݃૑݄) Flux / Redux / MVIח ੉۠Ѣҳա 3о૑ ইఃఫ୛ ৘दܳ ా೧ UDA Ӕࠄਸ Ҋ޹೧ࠁदӝܳ ߄ېਃ!
  3. ੑ۱ јन ੺ݎ ੘স ੑ۱ јन ੘স ੑ۱ јन ੘স

    ੑ۱ јन Ѿҗܳ ৘࢚ೡ ࣻ হ׮! դ ૒੽ јन!
  4. ޖ঺੉ ޙઁੌө? - Viewী ৔ೱਸ ઱ח State ߸ചо ৈ۞Ҕীࢲ ੌযթ

    - ࠺زӝ۽ ੌযաח State ߸ച द੼ਸ ৘࢚ೡ ࣻ হ਺ ੑ۱ јन ੘স ׮ࣻ੄ ੑ۱ ঱ઁ ՘զ૑ ݽܰח ੘স ੑ۱ јन դ ૒੽ јन!
  5. ޖ঺੉ ޙઁੌө? - Viewী ৔ೱਸ ઱ח State ߸ചо ৈ۞Ҕীࢲ ੌযթ

    - ࠺زӝ۽ ੌযաח State ߸ച द੼ਸ ৘࢚ೡ ࣻ হ਺ - ݽ؛ীࢲ Ѿ੿غח Stateܳ Viewীࢲ ֈѹ߉ই ٮ۽ ҙܻೞӝ ٸޙী Ѻରо ࢤӣ ੑ۱ јन ੘স ׮ࣻ੄ ੑ۱ ঱ઁ ՘զ૑ ݽܰח ੘স State ݽ؛ јनೡ ٸח ࢎप ׳ۄ૓ State ੑ۱ јन դ ૒੽ јन!
  6. - Viewী ৔ೱਸ ઱ח Stateח ೠ ߑೱਵ۽݅ ࣻ੿ೡ ࣻ ੓׮.

    ױߑೱ Uni-Directional Architecture (UDA) Core
  7. - Viewী ৔ೱਸ ઱ח Stateח ೠ ߑೱਵ۽݅ ࣻ੿ೡ ࣻ ੓׮.

    ױߑೱ - খ੄ ঘ࣌੉ ՘ա૑ ঋਵݶ ٍ ঘ࣌ਸ प೯ೞ૑ ঋח׮. زӝ੸ प೯ Uni-Directional Architecture (UDA) Core
  8. - Viewী ৔ೱਸ ઱ח Stateח ೠ ߑೱਵ۽݅ ࣻ੿ೡ ࣻ ੓׮.

    ױߑೱ - খ੄ ঘ࣌੉ ՘ա૑ ঋਵݶ ٍ ঘ࣌ਸ प೯ೞ૑ ঋח׮. زӝ੸ प೯ - Model਷ Stateܳ ߸ചदఃҊ, Viewח Stateܳ ଵઑ݅ ೠ׮. View৬ State ܻ࠙ Uni-Directional Architecture (UDA) Core
  9. UDA ઙܨ -Flux (Architecture by Facebook) -Redux (Library related Flux)

    -MVI (UDA Architecture in Android) 3о૑ ৘दܳ ా೧ UDAܳ ঌইࠇद׮!
  10. private void setButton() { btnAdd.setOnClickListener(v -> { String text =

    inputTodo.getText().toString(); if ("".equals(text)) return; actionCreator.create(text); inputTodo.setText(""); }); btnClear.setOnClickListener(v -> actionCreator.clear()); } View
  11. private void setButton() { btnAdd.setOnClickListener(v -> { String text =

    inputTodo.getText().toString(); if ("".equals(text)) return; actionCreator.create(text); inputTodo.setText(""); }); btnClear.setOnClickListener(v -> actionCreator.clear()); } View
  12. public class TodoActionCreator { public void create(String todo) { Dispatcher.dispatch(Action.with(TodoActions.TYPE_CREATE)

    .data(TodoActions.KEY_TEXT, todo)); } public void clear() { Dispatcher.dispatch(Action.with(TodoActions.TYPE_CLEAR)); } } public class TodoActions { public static final String TYPE_CREATE = "CREATE"; public static final String TYPE_CLEAR = "CLEAR"; public static final String KEY_TEXT = “KEY_TEXT"; } ActionCreator
  13. public class TodoActionCreator { public void create(String todo) { Dispatcher.dispatch(Action.with(TodoActions.TYPE_CREATE)

    .data(TodoActions.KEY_TEXT, todo)); } public void clear() { Dispatcher.dispatch(Action.with(TodoActions.TYPE_CLEAR)); } } public class TodoActions { public static final String TYPE_CREATE = "CREATE"; public static final String TYPE_CLEAR = "CLEAR"; public static final String KEY_TEXT = “KEY_TEXT"; } ActionCreator Action ࢤࢿ ߂ Dispatch
  14. public class Dispatcher { private static EventBus bus = EventBus.getDefault();

    public static void dispatch(Action action) { bus.post(action); } } Dispatcher
  15. public class Dispatcher { private static EventBus bus = EventBus.getDefault();

    public static void dispatch(Action action) { bus.post(action); } } Dispatcher
  16. public class TodoStore extends Store { private List<Todo> todos =

    new ArrayList<>(); @Subscribe public void onEvent(Action action) { switch (action.getType()) { case TodoActions.TYPE_CREATE: String text = (String) action.getData().get(TodoActions.KEY_TEXT); todos.add(new Todo(text)); emitChange(); break; case TodoActions.TYPE_CLEAR: todos.clear(); emitChange(); break; } } } Store
  17. public class TodoStore extends Store { private List<Todo> todos =

    new ArrayList<>(); @Subscribe public void onEvent(Action action) { switch (action.getType()) { case TodoActions.TYPE_CREATE: String text = (String) action.getData().get(TodoActions.KEY_TEXT); todos.add(new Todo(text)); emitChange(); break; case TodoActions.TYPE_CLEAR: todos.clear(); emitChange(); break; } } } Store ࠺૑פझ ۽૒ ࣻ೯ (State ߸҃)
  18. public class TodoStore extends Store { private List<Todo> todos =

    new ArrayList<>(); @Subscribe public void onEvent(Action action) { switch (action.getType()) { case TodoActions.TYPE_CREATE: String text = (String) action.getData().get(TodoActions.KEY_TEXT); todos.add(new Todo(text)); emitChange(); break; case TodoActions.TYPE_CLEAR: todos.clear(); emitChange(); break; } } } Store protected void emitChange() { Dispatcher.emitChange(changeEvent()); }
  19. @Subscribe(threadMode = ThreadMode.MAIN) public void onEvent(TodoStore.TodoChangeEvent event) { updateUI(); }

    private void updateUI() { adapter.setItems(store.getTodos()); } View Store੄ State ଵઑ
  20. Flux ੿ܻ - View -> ActionCreator -> Action -> Dispatcher

    -> Store -> View - Multiple Store - Storeо ࠺૑פझ ۽૒ਸ प೯ೠ׮. (Stateܳ ҙܻೠ׮.) - Mutable State - ೙ਃೡ ҃਋ ActionCreatorо Repository ৉ೡਸ ೠ׮.
  21. private void setButton() { btnAdd.setOnClickListener(v -> { String text =

    inputTodo.getText().toString(); if ("".equals(text)) return; store.dispatch(actionCreator.create(text)); inputTodo.setText(""); }); btnClear.setOnClickListener(v -> store.dispatch(actionCreator.clear())); } View
  22. private void setButton() { btnAdd.setOnClickListener(v -> { String text =

    inputTodo.getText().toString(); if ("".equals(text)) return; store.dispatch(actionCreator.create(text)); inputTodo.setText(""); }); btnClear.setOnClickListener(v -> store.dispatch(actionCreator.clear())); } View Store.dispatch() ૒੽ ഐ୹
  23. public class TodoActionCreator { public Action create(String todo) { return

    Action.with(TodoActions.TYPE_CREATE) .data(TodoActions.KEY_TEXT, todo); } public Action clear() { return Action.with(TodoActions.TYPE_CLEAR); } } ActionCreator
  24. public class TodoActionCreator { public Action create(String todo) { return

    Action.with(TodoActions.TYPE_CREATE) .data(TodoActions.KEY_TEXT, todo); } public Action clear() { return Action.with(TodoActions.TYPE_CLEAR); } } ActionCreator Action ࢤࢿ݅ ࣻ೯
  25. public class SimpleStore<S extends State> implements Store<S> { private S

    initialState; private Reducer<S> reducer; private SimpleStore() { actionsSubject.map(action -> reducer.reduce(initialState, action)) .doOnNext(s -> initialState = s) .subscribe(s -> statesSubject.onNext(s), Throwable::printStackTrace); } @Override public void dispatch(Action action) { actionsSubject.onNext(action); } @Override public Observable<S> asObservable() { return statesSubject; } } Store
  26. public class SimpleStore<S extends State> implements Store<S> { private S

    initialState; private Reducer<S> reducer; private SimpleStore() { actionsSubject.map(action -> reducer.reduce(initialState, action)) .doOnNext(s -> initialState = s) .subscribe(s -> statesSubject.onNext(s), Throwable::printStackTrace); } @Override public void dispatch(Action action) { actionsSubject.onNext(action); } @Override public Observable<S> asObservable() { return statesSubject; } } Store
  27. public class SimpleStore<S extends State> implements Store<S> { private S

    initialState; private Reducer<S> reducer; private SimpleStore() { actionsSubject.map(action -> reducer.reduce(initialState, action)) .doOnNext(s -> initialState = s) .subscribe(s -> statesSubject.onNext(s), Throwable::printStackTrace); } @Override public void dispatch(Action action) { actionsSubject.onNext(action); } @Override public Observable<S> asObservable() { return statesSubject; } } Store initialState۽ࠗఠ newState ࢤࢿ
  28. public class TodoReducer implements Reducer<TodoState> { @Override public TodoState reduce(TodoState

    oldState, Action action) { switch (action.getType()) { case TodoActions.TYPE_CREATE: TodoState newState = new TodoState(oldState); String text = (String) action.getData().get(TodoActions.KEY_TEXT); newState.getTodos().add(new Todo(text)); return newState; case TodoActions.TYPE_CLEAR: return new TodoState(); default: return oldState; } } } Reducer
  29. public class TodoReducer implements Reducer<TodoState> { @Override public TodoState reduce(TodoState

    oldState, Action action) { switch (action.getType()) { case TodoActions.TYPE_CREATE: TodoState newState = new TodoState(oldState); String text = (String) action.getData().get(TodoActions.KEY_TEXT); newState.getTodos().add(new Todo(text)); return newState; case TodoActions.TYPE_CLEAR: return new TodoState(); default: return oldState; } } } Reducer Reducerח ೞա੄ ೣࣻ
  30. public class TodoReducer implements Reducer<TodoState> { @Override public TodoState reduce(TodoState

    oldState, Action action) { switch (action.getType()) { case TodoActions.TYPE_CREATE: TodoState newState = new TodoState(oldState); String text = (String) action.getData().get(TodoActions.KEY_TEXT); newState.getTodos().add(new Todo(text)); return newState; case TodoActions.TYPE_CLEAR: return new TodoState(); default: return oldState; } } } Reducer
  31. public class TodoReducer implements Reducer<TodoState> { @Override public TodoState reduce(TodoState

    oldState, Action action) { switch (action.getType()) { case TodoActions.TYPE_CREATE: TodoState newState = new TodoState(oldState); String text = (String) action.getData().get(TodoActions.KEY_TEXT); newState.getTodos().add(new Todo(text)); return newState; case TodoActions.TYPE_CLEAR: return new TodoState(); default: return oldState; } } } Reducer ࠺૑פझ ۽૒ ࣻ೯ (initialState۽ࠗఠ newState ࢤࢿ)
  32. public class SimpleStore<S extends State> implements Store<S> { private S

    initialState; private Reducer<S> reducer; private SimpleStore() { actionsSubject.map(action -> reducer.reduce(initialState, action)) .doOnNext(s -> initialState = s) .subscribe(s -> statesSubject.onNext(s), Throwable::printStackTrace); } @Override public void dispatch(Action action) { actionsSubject.onNext(action); } @Override public Observable<S> asObservable() { return statesSubject; } } Store
  33. private void subscribeStore() { store.asObservable() .observeOn(AndroidSchedulers.mainThread()) .subscribe(this::updateUI); } private void

    updateUI(TodoState state) { adapter.setItems(state.getTodos()); } View Store੄ State ଵઑ
  34. Redux ੿ܻ - View -> ActionCreator -> Action -> Reducer

    -> Store -> View - 3ਗ஗: ױੌ Store, Immutable State, Functional Reducer - Viewীࢲ ૒੽ Store dispatchܳ प೯ - Single Store - Reducerо ࠺૑פझ ۽૒ਸ प೯ೠ׮. - Immutable State - Reducer খী ߹بӝמ Middleware ୶о оמ - ೙ਃೡ ҃਋ Middlewareо Repository ৉ೡਸ ೠ׮.
  35. Flux Redux Dispatcher ੓਺ Multiple Store Business logic in Store

    Mutable State Dispatcher হ਺ Single Store Business logic in Reducer Immutable State
  36. private PublishSubject<MviIntent> addIntent = PublishSubject.create(); private PublishSubject<MviIntent> clearIntent = PublishSubject.create();

    private void setButton() { btnAdd.setOnClickListener(v -> { addIntent.onNext(MviIntent.with(TodoActions.TYPE_CREATE) .data(TodoActions.KEY_TEXT, inputTodo.getText().toString())); inputTodo.setText(""); }); btnClear.setOnClickListener(v -> clearIntent.onNext(MviIntent.with(TodoActions.TYPE_CLEAR))); } private void initializeIntent() { presenter.processIntents(intents()); } public Observable<MviIntent> intents() { return Observable.merge(addIntent, clearIntent); } View
  37. private PublishSubject<MviIntent> addIntent = PublishSubject.create(); private PublishSubject<MviIntent> clearIntent = PublishSubject.create();

    private void setButton() { btnAdd.setOnClickListener(v -> { addIntent.onNext(MviIntent.with(TodoActions.TYPE_CREATE) .data(TodoActions.KEY_TEXT, inputTodo.getText().toString())); inputTodo.setText(""); }); btnClear.setOnClickListener(v -> clearIntent.onNext(MviIntent.with(TodoActions.TYPE_CLEAR))); } private void initializeIntent() { presenter.processIntents(intents()); } public Observable<MviIntent> intents() { return Observable.merge(addIntent, clearIntent); } View Intent ࠁղӝ
  38. private PublishSubject<MviIntent> addIntent = PublishSubject.create(); private PublishSubject<MviIntent> clearIntent = PublishSubject.create();

    private void setButton() { btnAdd.setOnClickListener(v -> { addIntent.onNext(MviIntent.with(TodoActions.TYPE_CREATE) .data(TodoActions.KEY_TEXT, inputTodo.getText().toString())); inputTodo.setText(""); }); btnClear.setOnClickListener(v -> clearIntent.onNext(MviIntent.with(TodoActions.TYPE_CLEAR))); } private void initializeIntent() { presenter.processIntents(intents()); } public Observable<MviIntent> intents() { return Observable.merge(addIntent, clearIntent); } View Intent ୊ܻ
  39. public class MviPresenter<S extends State> { private S initialState; private

    MviReducer<S> reducer; private BehaviorSubject<S> stateSubject = BehaviorSubject.create(); public void processIntents(Observable<MviIntent> intents) { intents .scan(initialState, (s, intent) -> reducer.reduce(s, intent)) .doOnNext(state -> initialState = state) .subscribe(stateSubject); } public Observable<S> states() { return stateSubject; } } Presenter
  40. public class MviPresenter<S extends State> { private S initialState; private

    MviReducer<S> reducer; private BehaviorSubject<S> stateSubject = BehaviorSubject.create(); public void processIntents(Observable<MviIntent> intents) { intents .scan(initialState, (s, intent) -> reducer.reduce(s, intent)) .doOnNext(state -> initialState = state) .subscribe(stateSubject); } public Observable<S> states() { return stateSubject; } } Presenter ࠺૑פझ ۽૒ ࣻ೯ (initialState۽ࠗఠ newState ࢤࢿ) Intent ୊ܻ
  41. public class MviPresenter<S extends State> { private S initialState; private

    MviReducer<S> reducer; private BehaviorSubject<S> stateSubject = BehaviorSubject.create(); public void processIntents(Observable<MviIntent> intents) { intents .scan(initialState, (s, intent) -> reducer.reduce(s, intent)) .doOnNext(state -> initialState = state) .subscribe(stateSubject); } public Observable<S> states() { return stateSubject; } } Presenter
  42. MVI ੿ܻ - View -> Intent -> Model -> View

    - Intentח Presenter ١ী ੓׮. - Multiple Store (Presenter) - Reducerо ࠺૑פझ ۽૒ਸ प೯ೠ׮. - Immutable State
  43. Flux Redux Action ݺद Dispatcher ੓਺ Multiple Store Business logic

    in Store Mutable State Action ݺद Dispatcher হ਺ Single Store Business logic in Reducer Immutable State MVI Action হ਺ Dispatcher হ਺ Multiple Store(Presenter) Business logic in Reducer Immutable State
  44. - Viewী ৔ೱਸ ઱ח Stateח ೠ ߑೱਵ۽݅ ࣻ੿ೡ ࣻ ੓׮.

    ױߑೱ - খ੄ ঘ࣌੉ ՘ա૑ ঋਵݶ ٍ ঘ࣌ਸ प೯ೞ૑ ঋח׮. زӝ੸ प೯ - Model਷ Stateܳ ߸ചदఃҊ, Viewח Stateܳ ଵઑ݅ ೠ׮. View৬ State ܻ࠙ Uni-Directional Architecture (UDA) Core ࠂण
  45. UDA ੢੼ ױߑೱ, View৬ State ܻ࠙, State ੷੢ࣗ ੌਗച ١ਵ۽

    State ҙܻী ੉੼ਸ ыח׮. -ৈ۞ ੑ۱(׮ܲചݶ,Service ١)ਵ۽ ੌযաח State ߸ചܳ ೠҔীࢲ औѱ ҙܻೡ ࣻ ੓׮ -State ߸҃૑੼੉ ݺഛೞৈ ٣ߡӦ੉ औ׮
  46. UDA ੢੼ যו ҃਋ী UDAܳ ࢎਊೡө? ױߑೱ, View৬ State ܻ࠙,

    State ੷੢ࣗ ੌਗച ١ਵ۽ State ҙܻী ੉੼ਸ ыח׮. -ৈ۞ ੑ۱(׮ܲചݶ,Service ١)ਵ۽ ੌযաח State ߸ചܳ ೠҔীࢲ औѱ ҙܻೡ ࣻ ੓׮ -State ߸҃૑੼੉ ݺഛೞৈ ٣ߡӦ੉ औ׮
  47. UDA ੢੼ ׮নೠ Inputਵ۽(ੑ۱ઙܨ,࠺زӝ ١) ߸ചо ੌযաח ࠂ੟ೠ Stateী ؀೧

    ࢎਊ যו ҃਋ী UDAܳ ࢎਊೡө? ױߑೱ, View৬ State ܻ࠙, State ੷੢ࣗ ੌਗച ١ਵ۽ State ҙܻী ੉੼ਸ ыח׮. -ৈ۞ ੑ۱(׮ܲചݶ,Service ١)ਵ۽ ੌযաח State ߸ചܳ ೠҔীࢲ औѱ ҙܻೡ ࣻ ੓׮ -State ߸҃૑੼੉ ݺഛೞৈ ٣ߡӦ੉ औ׮
  48. UDA ੢੼ ׮নೠ Inputਵ۽(ੑ۱ઙܨ,࠺زӝ ١) ߸ചо ੌযաח ࠂ੟ೠ Stateী ؀೧

    ࢎਊ -ࠂ੟ೠ Stateо হਵݶ ࢎਊೞ૑ ঋח Ѫ੉ જ׮. -ࠂ੟ೠ Stateী ؀೧ࢲ݅ ࠗ࠙੸ਵ۽ ࢎਊೡ ࣻ ੓׮. যו ҃਋ী UDAܳ ࢎਊೡө? ױߑೱ, View৬ State ܻ࠙, State ੷੢ࣗ ੌਗച ١ਵ۽ State ҙܻী ੉੼ਸ ыח׮. -ৈ۞ ੑ۱(׮ܲചݶ,Service ١)ਵ۽ ੌযաח State ߸ചܳ ೠҔীࢲ औѱ ҙܻೡ ࣻ ੓׮ -State ߸҃૑੼੉ ݺഛೞৈ ٣ߡӦ੉ औ׮
  49. ؘ੉ఠ ൒ܴਸ interfaceীࢲ Store۽ ߸҃ 1. Presenter ۽૒ റ Store۽

    dispatch ೠ׮. 2. Viewীࢲ Storeܳ ҳةೠ׮. UDA ѐ֛ਸ MVPীࢲ рױೞѱ ਽ਊ೧ࠁ੗
  50. public class TodoPresenter { private TodoRepository repository = new TodoRepository();

    private TodoStore store = TodoStore.get(); public void create(String text) { Todo todo = repository.create(text); store.create(todo); } public void clear() { repository.clear(); store.clear(); } } Presenter
  51. public class TodoPresenter { private TodoRepository repository = new TodoRepository();

    private TodoStore store = TodoStore.get(); public void create(String text) { Todo todo = repository.create(text); store.create(todo); } public void clear() { repository.clear(); store.clear(); } } Presenter ࠺૑פझ ۽૒ റ Store۽ Dispatch
  52. public class TodoStore { private List<Todo> todos = new ArrayList<>();

    private BehaviorSubject<List<Todo>> stateSubject = BehaviorSubject.create(); public void create(Todo todo) { todos.add(todo); stateSubject.onNext(todos); } public void clear() { todos.clear(); stateSubject.onNext(todos); } } Store
  53. public class TodoStore { private List<Todo> todos = new ArrayList<>();

    private BehaviorSubject<List<Todo>> stateSubject = BehaviorSubject.create(); public void create(Todo todo) { todos.add(todo); stateSubject.onNext(todos); } public void clear() { todos.clear(); stateSubject.onNext(todos); } } Store State ߸҃ ߂ ࠭ јन ঌܿ
  54. UDA ѐ֛ਸ MVPীࢲ рױೞѱ ਽ਊ೧ࠁ੗ ௾ ߸҃ হ੉ MVPী UDAܳ

    ࠗ࠙੸ਵ۽ ੸ਊೞ৓׮! ؘ੉ఠ ൒ܴਸ interfaceীࢲ Store۽ ߸҃ 1. Presenter ۽૒ റ Store۽ dispatch ೠ׮. 2. Viewীࢲ Storeܳ ҳةೠ׮.
  55. - Viewী ৔ೱਸ ઱ח Stateח ೠ ߑೱਵ۽݅ ࣻ੿ೡ ࣻ ੓׮.

    ױߑೱ - খ੄ ঘ࣌੉ ՘ա૑ ঋਵݶ ٍ ঘ࣌ਸ प೯ೞ૑ ঋח׮. زӝ੸ प೯ - Model਷ Stateܳ ߸ചदఃҊ, Viewח Stateܳ ଵઑ݅ ೠ׮. View৬ State ܻ࠙ Uni-Directional Architecture (UDA) Core ࠂण!!!
  56. Flux: http://facebook.github.io/flux Redux: https://redux.js.org ৉द Redux: https://www.slideshare.net/dalinaum/redux-55650128 MVI: http://hannesdorfmann.com/android/model-view-intent UDA:

    https://academy.realm.io/kr/posts/eric-maxwell-uni-directional-architecture-android-using-realm Sample Code: https://github.com/maryangmin/GDG-Flux-Redux-MVI Reference