Skip to content

Instantly share code, notes, and snippets.

@sockeqwe
Created January 23, 2017 23:31
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sockeqwe/92230cad2a9f56decacd5993df93d1ac to your computer and use it in GitHub Desktop.
Save sockeqwe/92230cad2a9f56decacd5993df93d1ac to your computer and use it in GitHub Desktop.
class PersonsModel {
// In a real application fields would be private
// and we would have getters to access them
final boolean loading;
final List<Person> persons;
final Throwable error;
public(boolean loading, List<Person> persons, Throwable error){
this.loading = loading;
this.persons = persons;
this.error = error;
}
// ... getters ...
}
class PersonsActivity extends MviActivity<PersonsPresenter> implements PersonsView {
private PersonsAdapter adatper;
// ... other things like onCreate() etc.
@Override public Observable<Boolean> load() {
return Observable.just(true);
}
@Override public void render(PersonsModelWithDiff viewState){
if (viewState.isLoading() ) {
// Show Loading
loadingView.setVisisbility(View.VISIBLIE)
erroView.setVisibility(View.GONE);
recyclerView.setVisibility(View.GONE);
} else if (viewState.getError() != null) {
// Show Error
loadingView.setVisisbility(View.GONE)
erroView.setVisibility(View.VISIBLE);
recyclerView.setVisibility(View.GONE);
} else if (viewState.getPersons() != null ){
// Show Content (RecyclerView)
adapter.setPersons(viewState.getPersons());
viewState.getDiffResult().dispatchTo(adapter);
loadingView.setVisisbility(View.GONE)
erroView.setVisibility(View.GONE);
recyclerView.setVisibility(View.VISIBLE);
} else {
throw new IllegalStateException("Don't know how to render "+viewState);
}
}
}
// This class is responsible to load a list of persons from backend
class PersonsInteractor {
private Backend backend;
public Observable<PersonsModel> loadPersons(){
return backend.getPersons() // Executes an http call i.e. with retrofit; returns Observable<List<Person>>
.map( persons -> new PersonModel(false, persons, null) )
.startWith( new PersonModel(true, null, null) ) // Indicates Loading
.onErrorReturn( error -> new PersonModel(false, null, error) ); // Indicates Error
}
}
class PersonsModelWithDiff {
// In a real application fields would be private
// and we would have getters to access them
final boolean loading;
final List<Person> persons;
final DiffResult result;
final Throwable error;
public(PersonModel originalModel, DiffResult diffResult){
this.loading = originalModel.getLoading();
this.persons = originalModel.getPersons();
this.error = originalModel.getError();
this.diffResult = diffResult;
}
// ... getters ...
}
class PersonsPresenter extends MviBasePresenter<PersonsView, PersonsModelWithDiff> {
private final PersonsInteractor interactor;
// This will interally hold a list to the previous List<Person>;
// However, that means that the function using this callback is not pure anymore (because it is a sideeffect to hold internally previous List<Person>
// To make it pure one could use RxJava scan operator.
private final DiffUtil.Callback callback;
public void bindIntents(){
Observable<PersonsModelWithDiff> observable = intent(PersonsView::load)
.flatMap( ignored -> interactor.load() )
.map( personModel -> {
if (personModel.getPersons() != null)
return new PersonsModelWithDiff(personModel, DiffUtils.calculateDiff(callback));
else
return new PersonsModelWithDiff(personModel, null);
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
subscribeViewState(observable, PersonsView::render);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment