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

MVP+Reactive+Dagger

 MVP+Reactive+Dagger

A general presentation about the advantages of Model View Presenter pattern, Reactive and Dagger 2 in our projects.

Yair Carreno

April 06, 2016
Tweet

More Decks by Yair Carreno

Other Decks in Technology

Transcript

  1. MVP

  2. Advantages MVP • Activities and Fragments become very lightweight. Their

    only responsibilities are to set up/update the UI and handle user events. Therefore, they become easier to maintain. • We can now easily write unit tests for the presenters by mocking the view layer. Before, this code was part of the view layer so we couldn’t unit test it. The whole architecture becomes very test-friendly. • If the data manager is becoming bloated, we can mitigate this problem by moving some code to the presenters.
  3. Implementing MVP public class MainActivity extends BaseActivity implements MainMvpView {

    @Inject MainPresenter mMainPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... mMainPresenter.attachView(this); mMainPresenter.loadMovies(); } @Override public void showMovies(List<Movie> movies) { mMoviesAdapter.setmMovies(movies); } } MainActivity.java
  4. Implementing MVP public interface MainMvpView extends MvpView { void showMovies(List<Movie>

    movies); void showMoviesEmpty(); void showError(); void syncMovies(String title); } MainMvpView.java
  5. Implementing MVP public class MainPresenter extends BasePresenter<MainMvpView> { @Override public

    void attachView(MainMvpView mvpView) { super.attachView(mvpView); } @Override public void detachView() { ... } public void loadMovies() { ... } } MainPresenter.java public void loadMovies() { compositeSubscription.add(mDataManager.getMovies() ... .subscribe(response -> { if (response.isEmpty()) { getMvpView().showMoviesEmpty(); } else { getMvpView().showMovies(response); } }, throwable -> { Timber.e(throwable, "There was an error loading movies."); getMvpView().showError(); })); } All logic in my Presenter
  6. Reactive world In a reactive world, we can't just wait

    for the results of the events, we provide a clear sequence of reactions to the events that are going to happen. - Observable - Observer - Subscriber - Subscriptions - Subjects
  7. Advantages Reactive • RxJava Observables and operators remove the need

    for having nested callbacks. • The interactors (DataManager) takes over responsibilities that were previously part of the view layer. Hence, it makes Activities and Fragments more lightweight. • Moving code from Activities and Fragments to the DataManager and helpers means that writing unit tests becomes easier. • Clear separation of responsibilities. Helper classes or the interactors (DataManager) can be easily mocked.
  8. Implementing Reactive public void loadMovies() { checkViewAttached(); compositeSubscription.add(mDataManager.getMovies() .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io())

    .subscribe(response -> { if (response.isEmpty()) { getMvpView().showMoviesEmpty(); } else { getMvpView().showMovies(response); } }, throwable -> { Timber.e(throwable, "There was an error loading the movies."); getMvpView().showError(); })); } loadMovies() method in MainPresenter.java Observable Subscriber (Observer) Subscription
  9. Implementing Reactive public void loadMovies() { checkViewAttached(); compositeSubscription.add(mDataManager.getMovies() .observeOn(AndroidSchedulers.mainThread()) .subscribeOn(Schedulers.io())

    .subscribe(response -> { if (response.isEmpty()) { getMvpView().showMoviesEmpty(); } else { getMvpView().showMovies(response); } }, throwable -> { Timber.e(throwable, "There was an error loading the movies."); getMvpView().showError(); })); } Result over main thread Process over other thread Any error Response loadMovies() method in MainPresenter.java
  10. Implementing Reactive public Observable<List<Movie>> getMovies() { return mDatabaseHelper.getMovies() .distinct(); }

    Observable in DataManager.java public Observable<List<Movie>> getMovies() { return mDb.createQuery(Db.MovieTable.TABLE_NAME, "SELECT * FROM " + Db.MovieTable.TABLE_NAME) .mapToList(cursor -> Db.MovieTable.parseCursor(cursor)); } Observable in DatabaseHelper.java Subject = Observer + Observable
  11. SearchView with Reactive public void loadSearch() { mCompositeSubscription .add(RxSearchView.queryTextChanges( ((MainActivity)

    getMvpView()).getSearchView()) .filter(charSequence -> !TextUtils.isEmpty(charSequence)) .throttleLast(100, TimeUnit.MILLISECONDS) .debounce(200, TimeUnit.MILLISECONDS) .onBackpressureLatest() .observeOn(AndroidSchedulers.mainThread()) .map(s -> s.toString()) .subscribe(getMvpView()::syncMovies, throwable -> { getMvpView().showError(); })); } SearchView
  12. Without Dagger Activity Fragment Service View Object Bus MovieApi Network

    Client Disk Cache Picasso SessionManager PreferencesHelper
  13. Implementing Dagger ApplicationComponent ApplicationModule Activity Fragment Service View Object ActivityComponent

    ActivityModule NetworkModule StorageModule Bus MovieApi Application @ApplicationContext Context Activity @ActivityContext Context PreferencesHelper
  14. Advantages Dagger • Easier unit and integration testing because the

    dependency graph is created for us, we can easily swap out modules that make network responses and mock out this behavior. • Since dependencies can be injected and configured externally we can reuse those components. • We can just change the implementation of any object without having to make a lot of changes in our codebase, since that object instantiation resides in one place isolated and decoupled.
  15. Dagger: Components @Singleton @Component(modules = {ApplicationModule.class, NetworkModule.class}) public interface ApplicationComponent

    { void inject(SyncService syncService); ... MovieApiInterface movieApi(); } ApplicationComponent.java @PerActivity @Component(dependencies = ApplicationComponent.class, modules = ActivityModule.class) public interface ActivityComponent { void inject(MainActivity mainActivity); } ActivityComponent.java
  16. Dagger: Modules @Module public class ApplicationModule { protected final Application

    mApplication; public ApplicationModule(Application application) { this.mApplication = application; } ... @Provides Application provideApplication() { return mApplication; } } ApplicationModule.java @Module public class ActivityModule { private Activity mActivity; public ActivityModule(Activity activity) { this.mActivity = activity; } @Provides @ActivityContext Context provideContext() { return mActivity; } } ActivityModule.java
  17. Dagger: Scopes & Qualifiers @Scope @Retention(RetentionPolicy.RUNTIME) public @interface PerActivity {

    } PerActivity.java @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface ApplicationContext { } ApplicationContext.java @Qualifier @Retention(RetentionPolicy.RUNTIME) public @interface ActivityContext { } ActivityContext.java
  18. References • Clean Architecture by Pedro Vicente and Jorge Barroso:

    https://goo.gl/U8M8B9 • Dependency Injection with Dagger 2 by Jake Wharton: https://goo.gl/pweC7P • Grokking RxJava, Part 1: The Basics by Dan Lew: http://goo.gl/60AYDU • Android Application Architecture by Iván Carballo: https://goo.gl/6xX2oW