Einstein once said:
Only two things are infinite, the universe and the number of design patterns used for Android development.
He’s still got it.
But seriously, architecting an Android app has always been a mess. There was no “official” standpoint about that and everyone was doing what they felt was good. And that’s good, because there is nothing like an absolute truth and every app and every developer is born different, but without a common and solid starting point, this quickly escalated to a jungle, making it really hard for new developers to find their way.
If you are still here, I’d like to give to you an idea of how messy the Android development world is. Just quickly, because I want to talk about the good stuff too.
Everyone with a little experience in programming knows Model View Controller, and knows that it’s a good design pattern overall. It allows a good separation between the logic and the UI of your program, it’s easy to understand and to implement.
So people started applying MVC to Android. What could possibly go wrong?
Some consider Activities and Fragments as the Controllers and the XML layout as the View. For others, the Activity is the Controller and the Fragment that lives within it is the View. Others tend to do everything in the Activity, without even relying on the models (even if this is not technically MVC 🤷).
This is me going through that stuff some years ago:
Some more experienced developers started using the Model View Presenter pattern and things were getting better. With MVP there is a clearer distinction between the components: Activities and Fragments are the View, the Presenter is an external class, usually with no Android-related stuff in it.
But still, only a few used MVP and for new developers the way to go was still MVC. Well, actually it was one of the random architectures that I described before, let’s just call it MVC for simplicity. But then…
Google steps in
Google acknowledges the issue and during Google I/O 2017 published the Architecture Components set of libraries alongside this image.
This diagram is a game-changer. This diagram is the first hint about a structure that Google ever gave us. In a single image, we can see the officially recommended design pattern: Model View ViewModel. The reactive programming pattern is embraced, through LiveData. A Repository is also used alongside a SQLite library, Room, and Retrofit for the network (instead of their own library Volley, by the way).
But MVVM wasn’t convincing us. Not fully, at least. With this structure, the View is supposed to observe the changes in the ViewModel’s data. This means that in the View you are going to have a very huge set of
ifs, not very “viewy”. The other option is to have different LiveDatas for the various parts of the UI, allowing each small part of the View to only look at a very specific data, but the ViewModels would increase in lines exponentially. We didn’t like either those solutions.
In Supermercato24 we spent quite some time searching and studying, to understand how to make it work for us without completely breaking all the advantages of the Architecture Components libraries. Then we found this article, that says:
If your ViewModel is holding too much code or has too many responsibilities consider […] moving some logic out to a presenter.
So… That’s it! Let’s add a Presenter between the View and the ViewModel! And so we did. This is what it looks like:
Isn’t this adding complexity? you might ask. That’s a good question.
When we were thinking about what structure to adopt in our apps, we evaluated also other patterns, including Clean Architecture.
At the end we decided to drop it because it felt too over-engineered to us. It is of course more structured and easier to maintain in the long term, but has a steeper learning curve, it’s harder to find new hires that already knows it and it forces us to have a lot of files for every feature.
This “Model View Presenter ViewModel” architecture that I’m showing you is the sweet spot for us. It is adding complexity over plain MVP or MVVM patterns, but actually not that much, it’s still way easier when compared to the Clean Architecture. Also it’s allowing us to have a better separation of concerns, like I’m going to explain below.
This is how it works:
- The View creates its Presenter (maybe it’s even
- The ViewModel is retrieved with the usual Architecture Components way. It’s referenced only in the Presenter.
- The communication between View and Presenter is the one that you can usually find in the MVP pattern. So dumb View that calls the Presenter for everything, the Presenter gives directives to the View.
- The Presenter observes LiveData changes provided by the ViewModel, does the magic
ifs and updates the View accordingly.
It’s important to specify the difference between the Presenter and the ViewModel. Why is there the need of two different components?
The Presenter contains the UI logic. For example, what should be done when I click on that button? How should the View react after an error comes from the network?
The ViewModel is responsible for the business logic. Is this item in the cart? What’s the
next step in the flow?
Let’s do a quick and simple example:
- The user clicks on the “Add to cart” button on an item.
- The View is dumb, it doesn’t know what to do, it panics, it asks help to the Presenter saying “hey, the user clicked to the add cart button, what should I do?“.
- Now the Presenter starts acting, handling the situation. It says to the View “don’t panic and show a loading”. Also it starts talking with the ViewModel, saying “ok then, let’s add this item to the cart“, but actually the Presenter doesn’t know what it means, because adding an item to the cart is not an easy task.
- The ViewModel is the boss here. It knows stuff. It knows for example that the item is a variable weight one (internal Supermercato24 jargon that usually means sold by weight), so you can’t just put
1quantity in the cart, but you have to put
0.3kilos. Also it needs to update the server with the new quantity. And save it in the Database. And some other stuff too.
- When the ViewModel finished its task, an update is posted in the LiveData and the Presenter is notified that everything is done. So now it can return to the View and say to it “you can remove the loading now, also start that fancy animation“.
- The View obeys.
And everything works like a charm.
As you may have noticed, the title says Part 1. In Part 2, I’ll try to show you how we implemented all this stuff. Well, yes, of course, with Android Studio, but we are developers. We are lazy. We don’t want to write everything everytime. So I’ll show you some nice tricks to speed up the development with this kind of structure. Trust me, I’m an engineer.