MVP: The Android Way!

Omer Ozer
TravelBank
Published in
5 min readJun 7, 2018
TravelBank x Android (Image : Dylan Wright )

As an Android developer, I’m sure you faced the task of writing code following an MVP pattern at some point. You also quickly realized that the Android platform by default isn’t exactly the most MVP friendly one. The fact that life-cycles and the communication between your components (Activities, etc…) are closely managed by the OS, make it a bit tricky to implement an MVP design. However, there are many ways MVP can still be achieved.

A common way of doing this is the old school way where all MVP components are started on an Activity. Activity is started by the OS, the activity starts it’s presenter, the presenter starts the model’s needed (or an interactor that manages them). This pattern often involves a Contract pattern where a blank/dummy interface called the “Contract” holds both the presenter and the view interfaces to expose their methods to each other. These interfaces are then implemented by the Activity and the presenter accordingly. You then pass the activity to the presenter .

So what are some pros and cons to this approach?

Pros:

  • Simplicity: requires no other libraries/frameworks
  • Shorter learning curve

Cons:

  • Components can’t have independent lifecycles
  • Requires extra code to be written (i.e activity callbacks need to be manually exposed to the presenter…)
  • Screen configuration changes may be tricky
  • Isn’t testable by default

This is definitely a very basic approach and I highly suggest anybody that is trying to master MVP to start off with this pattern until they’re fully familiar with the goals of MVP.

Another very common way of MVP that is a bit more complex and next level is the use of a dependency injection framework such as Dagger. The goal of Dagger isn’t exactly to create an MVP environment. It simply is a dependency injection framework. However, it can be designed in a way that your MVP and other components can be marked as dependencies and get injected where they’re needed. An example of it is that, a presenter gets marked as an dependency for an activity and when the activity is launched, it gets initialized and injected into your activity. The activity also gets injected into the presenter either directly or via a wrapper so its methods can be exposed to the presenter. This way however, provides a lot of other cool functionalities. Models can be tagged as singletons and have their own life-cycles. Testing becomes simpler as you can inject things in a testing environment also. So let’s quickly do a pros and cons.

Pros:

  • Dagger’s cool functionalities
  • Allows for complex dependency graphs
  • More testable/supports testability

Cons:

  • Requires a lot more code to be written to work
  • Adopting Dagger for a mature app will require a ton of refactoring
  • Dagger itself can be tricky and comes with it’s own learning curve

Dagger is definitely a great tool for dependency injection but I’d much rather use for dependencies only and not for a core framework for MVP.

This brings us to the next option which is a relatively new but a very Android-y framework that we (the Android devs at TravelBank) have developed specifically for MVP. We call it Knit. You can find the GitHub repository and docs here . We created Knit with one thing in mind: allow for easy and straightforward MVP on Android. Knit’s sole goal is to make all aspects of MVP a lot simpler and allow you to write much less code. We believe that MVP shouldn’t be a design bottleneck, ever.

Let’s dig deeper into Knit and create a sample app!

First thing first, you’ll have to add Knit to your gradle file. Depending on when you’re reading this, the version will change. So make sure to click the link above and get the most up-to-date version!

Knit is hosted by Jitpack so you’ll need to add Jitpack Maven repository to your repositories also.

After these steps and you synced your gradle files, you’re good to go. Let’s now initialize Knit inside our Application class.

Obviously I’m skipping some side steps here such as adding and registering these to your Manifest file. You should do that also.

Let’s quickly create an activity that will be the main view of our app.

To mark an activity as a view on Knit, you must annotate it with @KnitView . For simplicity sake, I am not using another library here. But Knit works fine with other libraries.

Now, let’s create the presenter that will handle our view.

Here, we create a class and have it extend KnitPresenter.class and annotate it with @Presenter. This class has two generic types attached. One of them is the view wrapper and the other is the accessor. The view wrapper is an auto-generated class that gives you access to your views all non-private, non-Android methods. The accessor gives you getter/setter access to non-private fields of all the models your presenter depends on. Here you can also see that your presenter has some methods you are already familiar with such as onCreate(). These callbacks make it easy for you to manage your resources and life-cycles. To learn more about how they work, visit Knit’s repository.

Now, to wrap it up, let’s create a model that simply mocks a rest call and returns a name.

Models must extend KnitModel.class and be annotated with @Model. Let’s quickly go over what we’ve done so far.

  1. We created a View/Activity
  2. We created a Presenter for our view.
  3. We created a Model

So how do these components interact with each other? How are their life-cycles managed? As you can see, everything seems to be automatic. We don’t worry about initializing our presenters or models. Knit does this for us. It also handles presenter to model requests. In this case we make a request to our model for a name, then get a response in our method that is annotated with @ModelEvent. All of this is handled under the hood by Knit.

Now Knit has many other features that can’t be covered in a single post. I’ll be posting more about it in the future. In the meantime, feel free to read our documentation to learn more about it!

The code written here can be found here on this repo . Follow our blog for more posts from TravelBank.

Best!

--

--