Futurice logo

Top 7 Tips for the Model in Android Architectures


Timo Tuominen

Senior Software Consultant

On Android many are now doing Model-View-Presenter (MVP) or Model-View-ViewModel (MVVM) architectures. I previously gave presentations about View Models and Olli Salonen wrote an article about them, but since then questions have arisen. What exactly is the Model? What’s the role of a Presenter? Are View Models even necessary anymore?

Tools for analysing architectures

Before going deeper into the specific questions let’s first have a look at architectures from a bird’s-eye view. In UI programming we can distinguish two separate qualities for the modules that an architecture deals with. The first one is how close to the view the code is. We can call this the view affinity of the code module.

What is a module? For our purposes a module is just a piece of independent code. In Java it could be a class that is instantiated by another part of the application, or it can simply be a pure function. RxJava is what we use to make the modules interact with each other.

All code in an application falls on some part of this spectrum. An architecture helps to name different segments of this spectrum and keep it nice and tidy through its convention.

The second quality is the life cycle of the module – at which times and how long it exists during the execution of the app. The life cycle normally depends on the platform we use as well as the navigation structure of the app. For instance, on Android a module made for a specific activity will be created with the activity and destroyed with it. On the other hand, we might have a module for a WebSocket connection that is only valid for each individual connection session.

To communicate between code modules with detached life cycles we would typically use a mediating layer that outlives both of the life cycles: for example the Application, which represent the life cycle of the Java VM. When switching from portait to landscape, the saved rotation state between Activity instances would often be hosted in the Application life cycle.

1. Understand the motivation of the architecture you have chosen

It’s good to use architectures that are known and already used in production, but make sure you ask the question “Why?” when figuring out how to apply them.

We can use the view affinity to get a better understanding of what is the responsibility of different parts of the architectures in the two popular ones, MVP and MVVM. Both of the architectures are focused on building a wall around the View to keep it from polluting the left side of the spectrum. The closer we are to the View the more difficult the code is to unit test and the less generic it becomes. View is the part that changes the most often and is the most susceptible to platform issues.

In MVP the Presenter normally takes a big chunk of responsibility populating and managing the View. The goal here is to reduce the View into nothing more than a drawing canvas while having the presentation logic in a separate module. What is less discussed in MVP is the role of the Model, which actually covers a big part of the spectrum.

In MVVM the View Model is the middle man between the Model and the View. Its role is to create the data for the View to show – but how it is presented is not of interest to the View Model. Again, while smaller than in MVP, the Model in this architecture is also not clearly defined.

2. The Model is an internal API for data

First of all, the Model is not the “data model class” POJO (plain old Java object). A more descriptive, albeit simplified, name for it could be the Data Layer. In reactive programming the Model is the place where the data comes from.

In terms of a mental model, the Model is much like a REST API inside of a client. It’s a central place for all of application data. Instead of an HTTP query, one would access it through a traditional function interface. You just need to know which function to call and the id of the data.

3. Use behavior Observables as data sources

Since in RxJava we would typically subscribe to an Observable to get data we will construct the Model to serve Observables. To get the last value we make sure the Observable acts as a Behavior. This means it emits the latest value immediately to new subscribers.

The Model thus becomes a “REST interface” that serves behavior observables. This enables anyone who uses the data to always get updates as well as the initial value. On the other hand, all consumers of the data are expected to handle updates to it. This is a good thing since it encourages writing code that reacts to change.

Do I have to release the subscriptions to the Model? Absolutely. When using a centralised Model with a very long life cycle, it is crucial to release all subscriptions to it when no longer needed. On Android you can do this in the Activity or Fragment life cycle. The only exceptions would be subscriptions that are made internally in the Model or that have similar life cycle to the Model (destroyed only when the app is destroyed).

4. Use the Repository Pattern to store and serve data

Inside of the Model we have something called a Repository. It’s a database that holds all of the relevant data and is able to broadcast updates to the data.

What kind of queries you allow to access the Repository is up to you: they can be based on an id, a property, or you can even have support for getting all of the contents of the Repository at once. Just make sure the Repository gives the latest data value and all of the subsequent updates to it – or at least communicate it clearly if it does not.

In an ideal world the same Model is shared between all parts of the app to make sure the app is always up to date. On Android, however, this means we would need to put them in a Content Provider of a similar container that all of the application processes can access and get updates from. One example of how this can be done is found in the Reark library, which is able to create Repositories (called Stores) backed by Content Providers.

5. Do not put additional Model logic in the Repository itself

One common mistake with the repository pattern is to think the entire Model is the Repository. This is not usually a good idea. The Repository is just a storage place and no logic should be put into it that does not deal with saving or retrieving data. If you need additional logic in the Model you can create a "reactive decorator" that processes all outgoing data values.

In terms of code it could look something along these lines:

    public Observable<Person> getPerson(Integer id) {
      return peopleRepository.getPerson(id).map(this::calculateAge);

Of course this solution would not update the age in case it changes during the execution of the app, but it could be easily resolved by using an observable of the systemTime with a combineLatest.

6. Use View Models as an extension to the Model

A View Model is a specific part of data processing. Where the Model ends and a View Model starts is a line in the water, but typically the difference is that a View Model is shorter-lived. It’s code that is more tied to the representation than business logic.

In the MVP architecture Presenters have a similar life cycle to View Models but are not meant to be used for processing the data. It can be tempting to start putting the data processing logic in the Presenter, but it is better to keep it separate: in MVP these data processing modules are sometimes called Interactors. In reality the names are only a way of communication and you should not get too stuck on them. Pick a name but try to keep the presentation separate from the data processing.

7. Don't be afraid to expand the architecture

The larger the application is, the less likely it is that one architecture is a perfect fit. In fact, on Android we might end up with a Model-View Model-Presenter-View pattern, or MVMPV in short. We present it here not to make it the next big thing, but to raise discussion on whether any of the architectures should be followed religiously. On a higher level it is actually better to talk about the possible roles code modules can have.

That said, MVMPV does work pretty well. You can see an example with the ChatClient on GitHub (chapter 9). Since this app supports rotation, a choice was made to expand the View Model life cycle to coexist with an Android platform Activity Loader (as originally described with a Presenter).


Choose an architecture that suits your needs and listen to the wishes and concerns of your collaborators. Try to work with the recommendations of the architecture – often there is a good point there. In case some part of your application grows beyond the chosen architecture, however, feel free to create new solutions that make your code more manageable. Every app is different and no architecture is perfect.

If you want to learn more check the Top 7 Tips for RxJava on Android or the upcoming book Grokking Reactive User Interfaces. For business needs Futurice also offers tailored workshops and development.

Recent blogs about Learning

Related Services and Topics

  • About
  • Services
  • Case Studies
  • Blog
  • Contact
  • Join us


© 2021 Futurice. All Rights Reserved | Privacy policy | Impressum

Futurice logo

Future. Co-created.