Implementing MVP with the new Dagger Android Injection API 2.11+

James Shvarts
ProAndroidDev
Published in
6 min readJul 19, 2017

--

Spotted in Provincetown, Massachusetts

This article is a follow-up to my recent post Demystifying the new Dagger Android Injection API. As promised, here is an example implementation of an MVP (Model-View-Presenter) pattern using the new Dagger API v2.11+. The code follows Clean Architecture and uses Dagger, Butterknife, RxJava 2. The entire source code can be found on GitHub at https://github.com/jshvarts/DaggerAndroidMVP.

Why MVP?

  1. MVP provides separation of concerns. Model deals with data. View is for displaying data and reacting to user input. Presenter allows for Model and View to communicate with each other. This modularization of components makes creating and maintaining the code significantly easier.
  2. MVP makes code more testable. When implemented properly, only the View part of your application contains Android framework-specific APIs — typically the View is implemented as an Activity, Fragment and the View is a passive view which contains zero to very little logic. Testing Android components requires Robolectric which is slower to run than tests running directly on the JVM and written with tools like JUnit and Mockito.
  3. MVP encourages modular pluggable architecture. The Presenter knows about the View only through an interface and therefore, one can easily swap the View implementation as long as the new View conforms to the interface. Overall, MVP design encourages Clean Architecture as you will see below.

Project setup

Here is a sneak peak of the class hierarchy:

I recommend feature-based package naming. For instance, when a new screen, such as Greeting Detail, is added, I’d create com.jshvarts.daggerandroidmvp.greeting package as a sibling of the com.jshvarts.daggerandroidmvp.lobby package and place all code specific to this screen there. I find that organizing packages this way greatly improves encapsulation, code readability, resulting in easier maintenance. Plus, it enables us to control visibility of the code by simply keeping interfaces, classes, their constructors and methods package-private.

We will be building this simple screen:

Clicking on the buttons will retrieve and update the greeting with either “Hello from LobbyGreetingRepository” or “Hello from CommonGreetingRepository”. The two repositories are defined in different scopes (the former is an application-scope while the latter is in LobbyActivity scope).

MVP contract

The contract interface below gives us a bird’s-eye view of the interaction between View and Presenter for the lobby screen.

Just looking at the LobbyGreetingContract we can get a pretty good idea about what user is able to do with the app. And, like in any contract where two parties enter in an agreement, the LobbyView and the LobbyPresenter agree on certain pre-defined interactions.

Base Presenter

I like having an abstract BasePresenter to be extended by other Presenters in the app. This way I can reduce the amount of code (and potentially bugs!) necessary for each Presenter to implement.

In the example below, we clear RxJava disposables (if any) in stop() of the BasePresenter so that the subclasses do not have to. You will see later that presenter.stop() is called from our View’s onStop() lifecycle callback.

Note that all of the method names are platform-agnostic — outside of the View layer we should try to avoid any Android-specific method names such as lifecycle callbacks like onStop().

Presenter Implementation

When Presenter deals with data exposed as RxJava streams, the Observables from the data layer become Subscriptions in the presentation layer.

In this particular example, I am using RxJava 2 and my data layer emits Single<String> which gets transformed into a Disposable by the presentation layer.

Here is the LobbyPresenter implementation:

Note that line subscribe(view::displayGreeting, view::displayGreetingError) is used to subscribe to a Single<String> stream and provides Success and Error callbacks to handle the results via method references. For this syntax to work, your app/build.gradle should contain the following snippet:

android {
...
defaultConfig {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

Alternatively, you could use Retrolambda Gradle plugin.

Injecting MVP components

Notice that all dependencies are provided at construction time. Here is the relevant Dagger code:

I could have set View on the Presenter after the latter is created via something like presenter.setView(this) in my Activity that serves as the View. This is what most MVP examples out there do. However, this would mean that every time my Presenter accesses the View, it would need to check whether the view instance is null prior to calling methods on it. Passing LobbyGreetingContract.LobbyView into the Presenter’s constructor solves this problem nicely.

Since the View is implemented as an Activity (see code below), the platform controls how and when it is instantiated and we rely on Dagger for to have the View in its graph when we need it.

This is how Dagger 2.11+ can provide the View for us. Note, because we cannot construct the Activity ourselves, the method used is abstract, I created a separate abstract @Module for it and added it to @ContributesAndroidInjector when injecting LobbyActivity (see source code below)

And this is what the updatedBuildersModule looks like now (if you find it confusing, refer to my previous article on Dagger 2.11+):

View implementation

As mentioned above, our View component is implemented in the form of Activity that implements LobbyGreetingContract.LobbyView:

Activity’s dependencies are provided via AndroidInjection.inject(this). Inside Activity#onStop() callback we call presenter.stop() which clears RxJava disposables (subscriptions). I could have used Activity#onDestroy() instead but I chose not to since that callback is not guaranteed to be called by the OS.

A word about Use Cases

Our Presenter works with use cases provided at construction time. LoadCommonGreetingUseCase and LoadLobbyGreetingUseCase are application and LobbyActivity scoped respectively.

The LobbyGreetingRepository is provided in the constructor via Dagger constructor injection (@Inject annotation). In the world of Clean Architecture, the Use Case class acts as an Interactor. It’s commonly implemented as a Command pattern which is what I did as well. of course, in a production app, LoadLobbyGreetingUseCase and LoadCommonGreetingUseCase would likely contain more logic, inject and utilize its own dependencies, etc. instead of simply delegating the call to repository.

SchedulersFacade?

Notice that LobbyPresenter utilizes SchedulersFacade, a custom proxy class I added to avoid Presenter having a dependency on Android-specific AndroidSchedulers. This removes the need for Robolectric when testing the Presenter. Alternatively, you can use RxAndroidPlugins hook built into RxJava 2.

Here is the code for SchedulersFacade:

Model

Our Model is rather boring and consists of only two small classes, CommonGreetingRepository and LobbyGreetingRepository where each of them provides only one method to return its own custom greeting. At the moment, the classes do not conform to the Repository pattern which is fine for our purpose since my goal with this article was to cover how MVP uses dagger.android.

Conclusion

I hope this article and the source code provided inspired you to integrate MVP pattern into your own apps using a combination of the new Dagger Android Injection API, Clean Architecture and RxJava. And, as always, your comments are appreciated!

Recommended reading

  1. The source code for this article is located at https://github.com/jshvarts/DaggerAndroidMVP. Note that the sample also includes loading indicator presentation logic implemented with help of RxRelay and how it’s controlled inside RxJava’s side effects methods.
  2. My article on MVVM architecture compares MVVM to MVP.
  3. My article Demystifying the new Dagger Android Injection API where you can find a more detailed description of the new Dagger setup.
  4. Model-View-Presenter: Android guidelines by Francesco Cervone.
  5. Clean Architecture is summarized here. If the concept is new to you, I recommend studying and adopting it whether your design pattern of choice is MVP, MVVM, MVC, or something else.
  6. MVP/Clean Architecture combo results in a more testable code so soon you may find yourself enjoying writing tests. My previous article on unit testing strategies Take Your Unit Tests to the Next Level may be helpful.

Visit my Android blog to read about Jetpack Compose and other Android topics

--

--