Boost your Android apps with Koin and Coroutines using MVVM in Kotlin

Adem Gunay
6 min readMay 2, 2019

--

Introduction

In this first workshop, we’re going to understand how to develop an Android application with good practices (making the app easily scalable/editable) using Koin and Coroutines basics. The main reason for choosing Kotlin language over Java for this project is because Kotlin is making Android development faster, better and concise.

As for the design pattern, there are basically two main ones for Android development: MVP and MVVM. We’ll be using MVVM because Google support it with their new LiveData and ViewModel libraries (Android Architecture Components).

The application will use theCatApi. It will consist on a simple MainActivity which will display a list of cat images 😺 To show how to scale the app, I might add some extra features on a next workshop if requested.

Let’s get started!

https://unsplash.com/photos/pWOdBS_l9LQ

Create a new project with an empty Activity. Name the app ‘DemoMeow’ and select Kotlin as the language. Set minimum API 21 and click finish.

We’re going to develop in Kotlin, so don’t forget to check Kotlin’s plugin and implement its dependencies if needed in the Gradle file:

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
apply plugin: 'kotlin-android-extensions'
///...dependencies { implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.20' ///...}

For this project, we’re going to add these following libraries in our Gradle dependencies:

dependencies {     ///...// Glide for loading and caching cat images
implementation 'com.github.bumptech.glide:glide:4.9.0'
kapt 'com.github.bumptech.glide:compiler:4.9.0'
// Retrofit as our REST service
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
// Koin for the dependencies injections
implementation 'org.koin:koin-android-viewmodel:2.0.0-rc-2'
// Coroutines for asynchronous calls (and Deferred’s adapter)
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.2.0'
// Coroutines - Deferred adapter
implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2'
}

The Model

https://unsplash.com/photos/pWOdBS_l9LQ

The response from our API will be a list of cats, thus our model will consist of a Cat object:

Note the @SerializedName which is going to tell retrofit that the JSON response’s url field has to be associated to our model’s imageUrl field.

We now need a class which will allow us to do operations with this model.
Good practice (and easier testing) requires to access the repository from an interface.
In order to have a clean architecture, we’ll create an interface called CatRepository and implement it in CatRepositoryImpl class. The interface will provide every operations functions related to cats (it has only one method for now — getCatList(), but if, for instance, later we want to retrieve a single cat, we’ll just have to update this repository adding getCat() signature in our interface and its logic in implementation).
CatRepository and its implementation will be written as follow:

The UseCaseResult class is going to be helpful to get the data if request succeeded or get the exception if our request failed.

Also, note the CatApi parameter in CatRepositoryImpl constructor, which is our REST interface. Create it as below:

Our ViewModel

https://unsplash.com/photos/iF2IHS0RVGM

The ViewModel class is designed to store and manage UI-related data in a lifecycle conscious way.

Let’s create a Kotlin class and name it MainViewModel and implement ViewModel from Google. It is going to be the viewModel associated to our MainActivity.

  • CoroutineScope has to be implemented in classes that are going to switch threads. With it comes CoroutineContext which we have to override.
  • MutableLiveData type is, as the name says, a mutable LiveData (we can set values).
  • SingleLiveEvent type is, in short, a LiveData that triggers only ones. More info here. (add this class from Google to the project → SingleLiveEvent.kt)
  • showLoading is a Boolean that our View will observe and update our progressBar according to its value.
  • catsList is our data list that our View will observe and display.

Next step is to fill our Cat object. To achieve it, we’ll have to setup our newly created API interface, CatRepository and viewModel with Koin.

Setting up Koin module

Let’s now create Modules file in which we’re going to setup our Koin’s modules. We’ll have to write the logic of how our classes are built in this file, so when we’ll need one of them, we’ll just tell Koin which one is needed and he will provide it for us.

Three points to note here:

  • Modules contains the classes that are going to be assembled inside appModule scope (in this case our Retrofit service and CatRepository).
  • To build Retrofit service, we will use createWebService() as singleton and our custom OkHttpClient as parameter with the function createWebService().
  • Our CatRepository is built here using Koin’s get() to satisfy constructor’s parameters. Whenever we’ll need it, Koin will provide it for us when we’ll use “by inject”.

We now need to add this appModules inside our Application to have access to it inside our app. Let’s create DemoMeowApplication class which will extend Application class and start Koin with our appModules:

We need to update our AndroidManifest to override default Application class. Also, don’t forget to add the INTERNET permission.
Update the manifest with the following lines:

   ///...
<uses-permission android:name="android.permission.INTERNET" />
<application>
android:name=".application.DemoMeowApplication"
///...
</application>

The View

https://unsplash.com/photos/hs9ln1kyWxA

Now that we have all our logic ready, we need to show them to the user.
This is where the View comes in. Its simple purpose is to show data.

We’ll start by preparing our Adapter which is going to handle the list to display:

Its item layout (item_cat.xml) :

Finally, let’s implement our MainActivity (the View) logic:

What is happening there?

First, We instantiate the viewModel using Koin. Then, we prepare our observers to observe viewModel’s data. Finally, we start our API request with viewModel.loadCats(), loading our data in viewModel which triggers the observer at lines 39 and updates the View’s adapter by calling updateData().

MainActivity’s layout (activity_main.xml):

Now you can run the app and enjoy a list of kittens 😺

This implementation remains basic but you’ve covered how to implement dependency injections with Koin using Coroutine to switch thread (MAIN/IO) to make an API call, retrieving data and displaying them with the MVVM pattern.

Feel free to add some implementation to grow this app and deepen your understandings. Here are some ideas: an onImageClick event, activity communications with a SecondActivity, loading more items on scroll, etc.

Here is the GitHub repository, make sure to checkout on the proper commit by using this command line inside DemoMeow repository:
git checkout 430211e

Thanks for reading and I hope you’ve learned something useful for your current/future developments! Don’t forget to clap if it was the case ;)
I may also add new features later on.

You can thank me with a coffee too! 😋

--

--

Adem Gunay

Android/Flutter developer @OOZOU Huge passion for mobile development. Clean Code addict.