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

Model-View-Intent

 Model-View-Intent

Andrdoid GDG Meetup 24th of Jannuary 2017

Avatar for Hannes Dorfmann

Hannes Dorfmann

January 24, 2017
Tweet

More Decks by Hannes Dorfmann

Other Decks in Programming

Transcript

  1. class PersonsPresenter extends Presenter<PersonsView> { public void load(){ getView().showLoading(true); //

    Displays a ProgressBar backend.loadPersons(new Callback(){ public void onSuccess(List<Person> persons){ getView().showPersons(persons); // Displays a list of Persons } public void onError(Throwable error){ getView().showError(error); // Displays a error message }); } }
  2. class PersonsModel { private final boolean loading; private final List<Person>

    persons; private final Throwable error; public(boolean loading, List<Person> persons, Throwable error){ this.loading = loading; this.persons = persons; this.error = error; } // ... getters ... }
  3. class PersonsPresenter extends Presenter<PersonsView> { public void load(){ getView().render( new

    PersonsModel(true, null, null) ); backend.loadPersons(new Callback(){ public void onSuccess(List<Person> persons){ getView().render( new PersonsModel(false, persons, null) ); } public void onError(Throwable error){ getView().render( new PersonsModel(false, null, error) ); } }); } }
  4. public class SearchFragment extends Fragment implements SearchView { ... @Override

    public Observable<String> searchIntent() { return RxSearchView.queryTextChanges(searchView) // Thanks Jake Wharton .filter(queryString -> queryString.length() > 3) .debounce(500, TimeUnit.MILLISECONDS); } }
  5. public class SearchFragment extends Fragment implements SearchView { ... @Override

    public void render(SearchViewState viewState) { if (viewState.isLoading()) { renderLoading(); } else if (viewState.getResult() != null) { renderResult(viewState.getResult()); } else if (viewState.getError() != null) { renderError(); } else { throw new IllegalArgumentException("Don't know how to render viewState"); } } }
  6. // Mosby 3.0 public class SearchPresenter extends MviBasePresenter<SearchView> { private

    final SearchInteractor searchInteractor; @Override protected void bindIntents() { Observable<SearchViewState> search = intent(SearchView::searchIntent) .flatMap(searchInteractor::search) subscribeViewState(search, SearchView::render); } }
  7. public class SearchInteractor { SearchEngine searchEngine; // Makes http calls

    public Observable<SearchViewState> search(String searchString) { return searchEngine.searchFor(searchString) // Observable<List<Product>> .map(products -> new SearchViewState(false, products, null)) .startWith(new SearchViewState(true, null, null)) .onErrorReturn(error -> new SearchViewState(false, null, error)); } }
  8. public class SearchInteractor { SearchEngine searchEngine; // Makes http calls

    public Observable<SearchViewState> search(String searchString) { return searchEngine.searchFor(searchString) // Observable<List<Product>> .map(products -> new SearchViewState(false, products, null)) .startWith(new SearchViewState(true, null, null)) .onErrorReturn(error -> new SearchViewState(false, null, error)); } }
  9. public class SearchInteractor { SearchEngine searchEngine; // Makes http calls

    public Observable<SearchViewState> search(String searchString) { return searchEngine.searchFor(searchString) // Observable<List<Product>> .map(products -> new SearchViewState(false, products, null)) .startWith(new SearchViewState(true, null, null)) .onErrorReturn(error -> new SearchViewState(false, null, error)); } }
  10. public class SearchInteractor { SearchEngine searchEngine; // Makes http calls

    public Observable<SearchViewState> search(String searchString) { return searchEngine.searchFor(searchString) // Observable<List<Product>> .map(products -> new SearchViewState(false, products, null)) .startWith(new SearchViewState(true, null, null)) .onErrorReturn(error -> new SearchViewState(false, null, error)); } }
  11. public class SearchInteractor { SearchEngine searchEngine; // Makes http calls

    public Observable<SearchViewState> search(String searchString) { return searchEngine.searchFor(searchString) // Observable<List<Product>> .map(products -> new SearchViewState(false, products, null)) .startWith(new SearchViewState(true, null, null)) .onErrorReturn(error -> new SearchViewState(false, null, error)); } }
  12. public class SearchInteractor { SearchEngine searchEngine; // Makes http calls

    public Observable<SearchViewState> search(String searchString) { return searchEngine.searchFor(searchString) // Observable<List<Product>> .map(products -> new SearchViewState(false, products, null)) .startWith(new SearchViewState(true, null, null)) .onErrorReturn(error -> new SearchViewState(false, null, error)); } }
  13. Cam searchIntent filter() flatMap() startWith( new Loading() ) L map(

    new SR() ) SR view.render( SearchViewState.SearchResult ) Cam C Ca Cam Cam
  14. Cam searchIntent filter() flatMap() startWith( new Loading() ) L map(

    new SR() ) SR view.render( SearchViewState.SearchResult ) Cam C Ca Cam Cam
  15. Cam searchIntent filter() flatMap() startWith( new Loading() ) L map(

    new SR() ) SR view.render( SearchViewState.SearchResult ) Cam C Ca Cam Cam
  16. class HomePresenter extends MviBasePresenter<HomeView> { private final HomeFeedLoader feedLoader; @Override

    protected void bindIntents() { Observable<PartialState> firstPage = ... ; Observable<PartialState> pullToRefresh = ... ; Observable<PartialState> nextPage = ... ; Observable<PartialState> loadMoreFromCategory = ... ; Observable<PartialState> allIntents = Observable.merge(firstPage, pullToRefresh, nextPage, loadMoreFromCategory); Observable<HomeViewState> stateObservable = allIntents.scan(this::viewStateReducer) subscribeViewState(stateObservable, HomeView::render); }
  17. public HomeViewState reducer( HomeViewState previous, Foo foo ) { HomeViewState

    newState; // compute the new State // by taking previous state and foo into account return newState; }
  18. CONCLUSION • Model reflecting State • Unidirectional data flow •

    Pure Functions • Readable Code • Easy to test : assertEquals( expectedModel, model );