Deep dive into Android Clean MVVM Architecture — Part II

Ali Shobeyri
Daresay
Published in
5 min readDec 1, 2022

Notice: first read Part I

Ok, now it’s time for some coding 💻

Let’s first clone the project from GitHub

I will show you the feature “search” and together we can see how can we achieve to create a powerful fully Clean Architecture app in Android 🤖

Here we have “core”, “features” and “app” modules. The features module have sub-modules that are the different parts of our app. For example, “search” is a feature that I developed earlier. Every feature has its own sub-module as well, “data”, “domain” and “UI”. Complex? Don’t worry, it’s like a piece of cake when you understand it.

Let’s start from the bottom, the domain layer :

On every domain module we have 3 packages :

Model

It is the same as “Entity” in clean architecture, we put our model data here and sometimes some utils functions and similar.

Repository

Here we keep all repositories related to the “search” feature. As you can see they are interfaces, not classes, why? Because we may want to create multiple implementations of them (for example if we want to create tests for the app we must create a fake repository based on this interface).

Here we define what we want (SearchModel) and what we should pass to get that model (q : String).

You can see I created a wrapper class called “Domain” here :

Domain is a sealed class representing states of requesting data, once we request data the app first returns a “Progress” state so then we can show a loading indicator. When the data is ready it will give us a “Result”, you can see “Result” has a model of kotlin.Result type (stupid naming, sorry, I should call it another thing) which can show us if the request was a failure or a success.

Use-Case

The last part is Use-Case.

Whenever we invoke our Use-Case, then the repository will return the proper data we want ✅

Notice: if you don’t know about Flow (a combination of Flow and Coroutines behave like RxJava, this term is called Reactive programming), read this link, you can find some examples on my GitHub too.

Every use case is extended from “MotherUseCase” :

Here we have three different Use-Cases, if we only have input or output we use the two bottom ones. If we have both input and output we use MotherUseCase<in Input, Output>.

That’s all about the domain layer. As you can see in the domain layer there are just some “definitions” and not real business logic. Here we just define what we want but we won’t tell how we want it!

Notice: Every domain module should add baseDomain as a dependency in the Gradle.

Notice II: Domain layer is pure Kotlin or Java

Let’s move to the data layer.

Data

On every data layer, we have 4 packages. DI is for dependency injection and we won’t dive into that in this article. The other ones are:

  • Datasource — This is a list of API services or database objects (DAOs) :
  • Model–Here is a list of our Network models. You might notice that we already have these on the “domain” layer, if we want to achieve clean architecture, we’d better separate network responses from our real models (you can ignore it too). The reason is that sometimes the network responses might be different from what we want to show to the user, so we have to cast them to the domain models.

Every DTO (data transfer object) must implement the “cast” interface (which is an interface from baseDomain), so we have something like this:

Since here our domain model is not different from the data model so we didn’t change anything. But as I said before sometimes there is a need to change some elements.

And now the most important part of data layer, the repository:

In the repository we create our implementations of the repository interfaces in the domain layer :

As you can see (and if you can recall I mentioned that earlier), we first emit or pass a “Progress” state, then with the help of the safeApi function (which is a helper function for catching errors and deciding if it is failure or success), we can emit a “Result” state to the next level of our app.

That’s all about the data layer.

Notice: every data layer must add baseData and baseDomain as its dependency in the Gradle

Notice II: every data layer must add its own domain as its dependency in the Gradle

Now it’s time for the UI layer.

UI Layer

Our application is “single activity”, so we shouldn’t add any Android Activity here (we only have one activity in the “App” module), but we must add our fragments and view-models.

Here is what is happening in a View-Model:

Here we can see what will be happened in the UI/View (fragment):

We simply collect data from the View-Model and react to it (in this case, filling an adapter for a recycler view).

That’s it! Now you must clone the project (or any other clean MVVM project) and explore it yourself 😎

Any comment? => s.shb.s.ali@gmail.com

Also, you can find me on LinkedIn: https://www.linkedin.com/in/iryebohs/

--

--