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

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 );