GroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupGroupSkip to Content

Version

Kotlin 1.2, Android 4.4, Android Studio 3

If you have some experience with Android development, Architecture Patterns may sound like an old-fashioned concept, which some smart guy has brought to the table just to put you down mercilessly. If I add the word VIPER to the discussion, you might think this sounds like a scam or click-bait. However, I assure you that once you get in-the-loop, you will appreciate how valuable it is to have proper code structure and organization.

In this tutorial, you will get to know the VIPER architecture pattern. You will start by understanding the ideas behind VIPER and how it fits into the Android framework. You will then put it into practice, implementing a sample app that adopts this architecture pattern and illustrates its benefits.

Do not fear the VIPER, just enjoy the bite! :]

Why are you (probably) reading this?

If the above introduction has grabbed your attention, it means you may feel as I used to just a few months ago. To sum up, you may have been developing Android apps for quite some time, reaching a high-level of code complexity and a considerable amount of lines of code in some of your projects. Then, at some point, you have gone through any of the following situations:

You get lost refactoring your own code when adding extra features.

You realize that there are too many null checks of the same field in different parts of the code.

Your classes and/or methods have increased their line length dramatically, largely exceeding the Rule of 30.

Some parts of your code are difficult or even impossible to cover with Unit Tests.

Your code becomes illegible to any other developer, since you are the only one able to “decipher” your business logic.

All of the above. :]

In my case, I was lucky enough to have a colleague around who pushed me to adopt architecture patterns in my projects. Please let me be that colleague for you.

When Android I met Architecture Patterns…

Let me start this section making an announcement upfront: I do not aim to put the blame on Android/Google for the lack of architecture patterns in my early projects. That responsibility is only mine.

It wasn’t me!

On the other hand, my impression is that, until recently, architecture patterns were never a main focus of the official Android documentation. In the old days, app structure was based around the four Android main application components: Activity (most cases), Service, Broadcast Receiver, and/or Content Provider. Later, Fragments came on the stage and became mainstream in many applications.

It was only last year that Google introduced the Android Architecture Blueprints project, in an attempt to give Android developers some organization and structure guidelines. You should definitely have a look at the repo to get a feeling for what’s available as guidance. In addition, Google also released the Android Architecture Components, which is “a collection of libraries that help you design robust, testable, and maintainable apps”. The Architecture Components are now part of Android Jetpack.

VIPER at a glance

In this section you will start diving into VIPER, an architecture pattern related to the Clean Architecture Paradigm. VIPER stands for View, Interactor, Presenter, Entity, and Router. This five-layer organization aims to assign different tasks to each entity, following the Single Responsibility Principle. The basic idea behind VIPER and other Clean Architecture patterns is to create a cleaner and more modular structure to isolate your app’s dependencies and improve the flow of data within your app.

Within the framework of an Android app, the VIPER layers are assigned according to the following scheme:

The View corresponds to an Activity or Fragment in the app. A goal is to make the View as dumb as possible, so that it only takes care of showing the UI.

The Interactor takes care of performing any action, when the Presenter says to.

The Presenter acts as a “Head-of-Department”. In other words, it commands any action making use of the Interactor, tells the View to display content, and orders the navigation to other screens using the Router.

The Router handles navigating to other screens during the app lifecycle.

Further theoretical details on this architecture pattern can be found in the following excellent reference.

Getting started

Enough talk! From this section onwards you will be creating an app named Chucky Facts. The goal is to give you a taste of VIPER in a real app, so that you can see how to handle certain common scenarios under this architecture.

Begin by downloading the starter project using the download button at the top or bottom of the tutorial. The starter project contains the basic skeleton app and some assets.

For didactic purposes, the code has been organized according to VIPER layer names (except for the Router). In a real application, it is common to structure the code in modules; in this particular example, they could be “SplashModule, “MainModule”, and “DetailModule”, for instance.

Build and run the starter project.

As you can see, there’s not a whole lot going on in the app yet.

App definition and description

This app is just a simple viewer which displays information fetched from a REST API. The data source is the well-known Internet Chuck Norris Database, which provides a large list of “facts” about Chuck Norris and his superior status.

The starter AndroidManifest.xml file shows three Activity items, one being SplashActivity which includes the MAIN intent-filter. Both MainActivity and DetailActivity will later extend from BaseActivity, which lets them include a Toolbar.

The app skeleton also includes the Joke class, in the entity package, and JokesListAdapter in the view.adapters package. These implementations do not directly relate to the topic of this tutorial, but feel free to have a look at them and analyze their behavior.

You can take some time to inspect the rest of the starter project and all the features included out-of-the-box (for example, the resource files strings.xml, dimens.xml, and styles.xml).

App modules and entities

In this tutorial, every module consists of a contract and several associated classes which implement the various VIPER layers. The contract describes which VIPER layers must be implemented in the module and the actions the layers will perform.

You can see there are two layers, defined as interfaces, that must be implemented: View and Presenter. Obviously, the functions declared inside the interfaces will be defined at some point in the code.

Main Module

View

Starting with MainActivity, make it extend BaseActivity() (instead of AppCompatActivity()), and implement the interface MainContract.View.

class MainActivity : BaseActivity(), MainContract.View {

After that, you will be required to implement some missing members. Hit Ctrl+I, and you will see that only one method corresponds to BaseActivity(), whereas the rest belong to MainContract.View.

You’ll need to hit Alt+Enter on PC or Option+Return on Mac to pull in the imports, and be sure to use the synthetic Kotlin Android Extensions for the view binding. Note that the presenter corresponds to the same module as the current view.

Finally, it is common when doing VIPER, that you inform the presenter when the view is visible, and make the instance null when the Activity is being destroyed. Add the following two lifecycle method overrides:

The class implements two interfaces declared in the MainContract: Presenter, which commands the whole module, and InteractorOutput, which allows you to define actions in response to what the Interactor returns.

You will need an Interactor instance to perform actions of interest.

When this function is called, the application will navigate to another screen (Detail Module) passing any data of interest; thus, it will be using the Router.

This callback defines what will happen when the view is finally loaded. Normally, you define here anything which happens automatically, with no user interaction. In this case, you will try to fetch data from the datasource through the REST API.

This function and the following will define what happens when the database query is addressed.

As for the presenter in the view, you need to make the presenter properties null in order to avoid any trouble when the system kills the module.

Setting aside the Router for further implementation, you can actually fill in the rest of functions.

For onQuerySuccess(data: List), add

view?.hideLoading()
view?.publishDataList(data)

and for onQueryError(),

view?.hideLoading()
view?.showInfoMessage("Error when loading data")

You simply handle the success or the error of the data query.

In onDestroy(), add

view = null
interactor = null

You make the properties null, as you did in the view layer.

Interactor

For onViewCreated() in the presenter, you want to query data from the remote datasource once the view loads. You need to first create the MainInteractor class in the interactor package.

Pull in dependencies via Alt+Enter on PC and Option+Return on Mac using import statements that begin with com.github.kittinunf. Of note in MainInteractor are the following:

Do not forget to make the class implement the proper interface, from the module contract.

loadJokesList() is a function which requires a lambda as input argument; this is technically the same as having a typical Java Callback.

In order to query data, the application uses Fuel, which is a Kotlin/Android library that allows easy and asynchronous networking. Another alternative would be using the well-known Retrofit. The query result is directly used by the lambda as input argument.

Do you remember the onViewCreated() function in MainPresenter that you left empty in the previous section? It is time now to fill it in.

The Router will bring arguments to this Activity from the previous module (remember listItemClicked(joke: Joke?) in the Main Module presenter), and they are retrieved and passed to the presenter once the view is ready. Add the following lifecycle overrides:

You can see that the backButtonClicked function is not defined yet, since it needs the module Router, whose implementation is pending.

Shaping the router

In some parts of this tutorial the term Router has appeared. However, you have never addressed its implementation, but why? The reason relates to how Android is designed. As mentioned before, the Router is the VIPER layer in charge of the navigation across the app views. In other words, the router is aware of every view existing in the app, and possesses the tools and resources to navigate from one view to another and vice-versa.

Keeping this in mind for each module, it would make sense to create the Presenter (the brain of the module), and then the rest of entities (View, Interactor, and Entity). Finally, the Router should wrap the Views up and somehow let the Presenter command the navigation.

This sounds perfectly reasonable, but things are a bit more complicated on Android. Think of what is the entry point of any Android application (corresponding to the the “main” method in other applications).

Yes, you are right, the entry point is that Activity which is marked with the appropriate intent-filter in the Android Manifest. In fact, every module is always accessed through an Activity, i.e. a View. Once created, you can instantiate any class or entity from it.

Therefore, the way Android has been designed makes it much more difficult to implement VIPER. At the end of the day, you will need a startActivity() function call to move to a new screen. The question that follows would be: can this be done in effortless way for the developer?

It’s possible that the new Jetpack Navigation Controller will help in this regard. But Jetpack is still in alpha, so, in the meantime, we’ll turn to a different tool.

Guided by a Cicerone

Having reached this point, it is important that you get to know Cicerone. I came across this excellent library not long ago, when trying to improve a VIPER implementation on Android. Although it is not flawless, I believe it comprises a few tools and resources which help to keep things neat and clear. It helps you make VIPER layers as decoupled as possible.

By default, applyCommand() handles the navigation logic. In this case, only Forward commands are processed.

forward is a custom function which undertakes navigation when command.screenKey matches.

At the end of the day, and due to Android design, you are going to need a startActivity somewhere, so that the navigation actually takes place.

So, you may be thinking this is just a wrapper that adds boilerplate to your code to do exactly what you used to do before. No doubt on the boilerplate, but now in any presenter, you can have a class member like

and use it easily. Go ahead and add it to both MainPresenter and DetailPresenter.

Do you remember listItemClicked(joke: Joke?) in MainPresenter? Now you are in position to add this beautiful line:

router?.navigateTo(DetailActivity.TAG, joke)

Magic!

It is time to implement the Router layer for every module, even for the Splash Module.

Try to do it yourself as an exercise, and check the final project if needed. As a hint, the navigator in SplashActivity looks a lot like the one in MainActivity. And the navigator in DetailActivity looks like:

App performance analysis

When started, the splash-screen appears for just a few seconds, and then it jumps directly to MainActivity. A ProgressBar appears while the list gets populated. You can gracefully scroll along the list, with no lag whatsoever. The Router works seamlessly allowing smooth transitions between screens, even handling the Toolbar "Back Arrow" events.

Testing the snake

One of the main benefits of using architecture patterns like VIPER is that it allows you to isolate the business logic in the Presenter. This entity ends up knowing nothing about Android. This is rather convenient since it makes unit testing much easier, reducing the amount of mocks you need to create.

Although there is not much business logic in this sample app, it is always a good practice to include some tests (both unit and UI tests). For that reason, the starter app comes with a pair of UI tests in MainActivityInstrumentedTest, in the androidTest folder:

The first test assesses that the RecyclerView gets populated, particularly checking that there is an item showing a "2" text message. In this particular case, it relates to the second item of the list.

The second test checks whether DetailActivity launches when clicking on a list item. For that purposes, the function assesses that once clicked, the RecyclerView does not show anymore.

In both test functions there is a call to waitForSplashScreen() from Utils.kt, which sleeps the thread for a few seconds to skip the splash-screen lapse.

Go ahead and click the green test arrow next to MainActivityInstrumentedTest. The Espresso UI tests will run on a device or emulator and you should see them both pass.

Where To Go From Here?

You can download the fully finished sample project using the download button at the top or bottom of the tutorial.

There are lots of good references to read about architecture patterns and VIPER in particular. I personally found rather solid foundations reading articles like this one, and this other.

Taking into account the latest novelties on Android, it would be interesting for you to get your hands on the Android Architecture Components, especially on components like Room, LiveData, and Navigation Controller. Give the official documentation a go, since as usual it is superb.

If you are interested in wrapping up the sample app you have just finished, it would be interesting to incorporate Dependency Injection using a library like Dagger. That will add completeness to the example, and will also help you to get consistency on your development projects by including one of the most popular frameworks for creating well-structured code.

We hope you enjoyed this tutorial on the VIPER architecture pattern, and if you have any questions or comments, please join the forum discussion below!