Clean and loosely coupled MVVM architecture in Android (Kotlin)

In the beginning, when I started exploring MVVM architecture I didn’t exactly find what I needed. Some of the illustrations were either too complicated or too basic. So this is an attempt of creating something just appropriate for the purpose.

THIS PROJECT IS ALSO AVAILABLE ON GITHUB. THE GITHUB LINK IS MENTIONED AT THE BOTTOM OF THIS ARTICLE.

NOTE: The entire project is available on Github.

This project is pretty simple with just a feature to sign in and sign up using Google firebase Authentication.

We won’t focus much on how to connect our application with firebase. You can go to the following link for the detailed documentation.
https://firebase.google.com/docs/android/setup

This is how the login and signup screen looks like.

Sign Up Screen
Login Screen

Let’s have a look at the XML of the two layouts.

Login layout :

Signup layout :

Let’s add the following dependencies to our App level build.gradle

The versions for the dependencies are the latest to the day when the code was written. Make sure to add everything else to the Gradle as mentioned in the above firebase documentation link.
Also add these two plugins for google services and Kotlin respectively in your App level build.gradle

apply plugin: ‘com.google.gms.google-services’

apply plugin: ‘kotlin-kapt’

Add your google-services.json generated by following the above-mentioned process. Once you are ready with the project setup, we are good to go.

This is our folder structure for the project.

Files in expanded form :

Let’s create a directory with the name ‘core’. It has a generic response listener interface that will listen to the response received from firebase or any other external sources (eg API).

It is a good practice to remove all hardcoded data from our project and keep it either as constant or into the strings resources.

NOTE: Never keep the strings that you are going to use as a key for firebase document, collection, or field names in string resource files. Instead, keep them as constants.

We have a data helper class to remove the dependency of our repository from the view model. We will later see how we can use this DataHelper class to get the instance of our repository in our view model without calling it directly. This makes our code loosely coupled.

Let us now create our login functionality. We have already created our XML layout for our login activity. Let’s have a look at our LoginActivity.

Here you can set up your toolbar (optional).

Our main focus should be on our LoginWithEmail() function.

Here we are observing two Live data error and user. If our observer finds some response in the error, an appropriate error message will be displayed on the snackbar. If there is no error, it will not have any value. When there is a response in user, it means that our login has been successful and the username of the person who logged in is received in user live data.

This is our data class for the authentication response.

Now let’s look at our view model. This class implements our ReponseListener of data type AuthResponseData and it overrides the onResponse() and onFailure() methods of our ResponseListener where it posts the value of our response from our firebase to our mutable live data whose value is being observed by our activity. Here we can see how we are using our DataHelper class to get the instance of our repository.

Our repository is the class where our application interacts with the outside data source or an internal database and fetches the data from them for our application.

Here to make our code further flexible we are not directly calling the repository. We are calling our actual repository via an interface. If we want to have another data source in the future we can add another class for it. This makes our code maintainable. Here LoginUsingFirebase is a child class of LoginRepository. Here if the login response from firebase is passed through our response listener to the view model where it is posted to the Live data which is constantly being observed in our Login Activity.

LoginRepository Interface :

Its child class LoginUsingFirebase() :

In the same way, now let's create the SignUp

SignUpActivity

SignUp View Model :

Data Class :

Repository :

SignUpRepository Interface :

SignUpUsingFirebase() :

So we have just wrapped up our Sign up part. Now let’s create our home screen.
Home Screen XML layout :

Let’s see the code of HomeActivity :

Home ViewModel :

Repository :

HomeRepository Interface :

LogoutUsingFirebase() :

We also have a splash screen that takes the user directly to the home screen on restarting the application if the user has already logged in. Let’s have a look at it.

For the sake of completion of the project, we also have a utility and a constants class.

Utility Class :

Constants class :

For other resources, we can go through the project on Github.

(In case you clone this project, follow the README.md to set up the project as I have removed my google-services.json file for security reasons.)

You can connect to me on LinkedIn https://www.linkedin.com/in/anantramanindia/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store