MVP, cooked the inFullMobile way

Jacek Kuźniarski
inFullMobile Blog
Published in
5 min readNov 21, 2017

The clean architecture topic gets quite a lot of press lately, and for a good reason. A sensible way of organizing code in Android projects was long overdue. Yes, books, conferences, and meetups — these had plenty to say on the topic. The thing is, the Android hive mind of blogs, tutorials, and news aggregators joined the clean arch train a bit late. We also think there were a few ideas that were not addressed by already existing solutions. We decided to roll our own in Kotlin and Java.

Doing it

Over a year ago, we finally sat down and worked out something that made our day-to-day work a bit easier and more organized. We had been using the MVP structure in the previous projects, but we finally wrapped up the idea into a library.

Ideas we decided to address

  1. Neither the Presenter, the View, the Model, the Fragment nor the Activity should become a god class.
  2. The View will not be implemented by a Fragment or Activity class — we do not want them to have too many responsibilities.
  3. All classes have to be testable.
  4. We will not be creating an interface for each Presenter and View. Besides easier mocking, we see no clear benefit in creating them.
  5. The base code should be simple enough to be generated automatically.
  6. We should not heavily depend upon external libraries.

Let’s dive in

Along with MVP, we are using a few other concepts. The Use Case Pattern is being used to encapsulate the domain logic. While The Repository Pattern is being used to encapsulate the I/O layer access.

To help you better understand our MVP approach, we will pepper in snippets of code.

View

View classes in our projects Bind&Display.

Your entry point, as in any View, is onViewsBound(). This method is triggered at the end of onCreate(bundle: Bundle). All your setup logic ( listeners, list adapters, and callbacks) should probably happen here.

bindView calls come from KotterKnife.

Base class with empty onViewsBound() override, along with a layout file, is auto-generated.

Presenter

Our Presenters Tie&Enact. They control the flow within a single screen by updating the model, subscribing to the model change, and, most importantly updating the view.

The presenter knows about the view via thepresentedView property.

We extend a base class for the presenter. Properly named class, with bind override is again, generated.

Model class

The model exposes the domain logic. It represents a state of the application, which is defined in the lower levels. The model also knows how to read and modify the application’s state through Use Cases.

In the code above, Use Case property and function had to be added. The base class has been auto-generated.

Activity & Fragments

We are left with a Fragment or an Activity. Those are pretty much all boilerplate and can be generated via templates we provide. Once created, they are rarely, if ever, modified.

Basics dependencies

Our Model knows about Use cases.

Our Presenter knows about the Model class and the View class.

Our View knows about the Presenter class.

Both the Presenter and the View class implementations are being injected into an implementation that extends one of the following: InFullMvpFragment, InFullMvpActivity.

Setup

Head on to the GitHub repository page and set up Gradle with

To use pure Java, you can skip the -kotlin part in the artifact's name.

This is a lot!

Fear not. We have created a set of templates to use right out of Android Studio.

It will generate all classes to get you started.

If you still have doubts, please check our samples. They will show you the simplest way of using an activity or fragment with our library.

Dependency Injection

We use (and like) Dagger a lot. While we’ve moved to version 2.10, we support injection setups as far as version 2.2. You can see sample setups for both here in our repository.

Unit Testing

One of the most often stressed points is the ability to easily create tests. Besides, having to use themockito-inline plugin to enable mocking of final classes, there is only one gotcha during testing.

Testing View

Set up the robolectric.properties file in thetest/resources directory.

As generics, you need to supply all the classes we’ve created above: the presenter, the view, and the activity/fragment.

Base classes for testing views are provided within infullmvp-basetest and infullmvp-kotlin-basetest packages.

Testing Presenter & Model

Writing tests for these is simple enough. Be sure to use Robolectric and its custom runner when using any Android classes.

The outcome

To sum up, we can go over the goals we wanted to achieve.

We will not be creating an interface for each Presenter and View.

Done.

View will not be implemented by Fragment or Activity.

We always wondered whether an activity would be a presenter since it controls the flow or a view since it presents a screen. We’ve opted for completely delegating these responsibilities away from activity classes.

Neither the Presenter, the View, the Model, the Fragment nor the Activity should become a god class.

Check. At an implementation level, we favour composition over inheritance. Each chunk of logic is clearly delegated.

All of it has to be testable.

Done, thanks to dependency injection. Additional work had to be only done for a base test view class (which we supply in the additional artifact).

Most importantly: all base pieces can be generated easily with a template.

Downsides

While we don’t like libraries that bring their own dependencies, we have made a sacrifice of pulling in an external code.

The first big thing is AppCompat, the behemoth that often lands in apps. We are using this as a dependency.

Dagger is another library that simplifies our work. Templates autogenerating the code assume you will be using Dagger, though you can roll your own object generation.

Finally, our Presenter class does know about some of the Android lifecycle methods. The presenter also knows about the Bundle class. It also has access to Context via it’s presentedView property.

Finally, you are done

Source: Giphy, https://giphy.com/gifs/CzbiCJTYOzHTW

Just not about yet.

A very cool duder, Jan Gonera, will be giving a talk about all of this. See him at Mobile Warsaw #55, in Warsaw, Poland. Make sure to drop in and say hi.

Some of us will also be at the TechCrunch Disrupt in Berlin, 2017. Give us a high five when you get there!

See an issue? Don’t understand something? Something does not work?
Hit us up on our GitHub repo by creating an issue or a pull request!

Jacek is an Android Wizard at inFullMobile, an international digital product design and development studio based in Warsaw, Poland.

Medium · Twitter · Dribbble · Stack Overflow · LinkedIn · Facebook · GitHub

--

--