Guide to learning Android Dev with Kotlin and Architecture Components (ViewModel, LiveData and Room)

February 26, 2018

This article assume you have prior Android development experience with Android Studio, since this topic is pretty huge already.

What is this guide?

I will explain what these tech are, why you should use them and where are the good resources to learn them.

Do you need this guide? Plenty of online tutorials I read while learning are half baked, not production ready code and fail to highlight some best practices. I will try to provide guidance to address these issues.

There shall be very little or no code here, since I would need to create a dozen of tutorials to show everything in action (I might create some later targeting specific topics). But I will show you where the good sample code are.

Kotlin

Why use Kotlin?

  • Modern, fun and productive language
  • Clean and concise code (less code)
  • Null safety (Kotlin’s type system is aimed to eliminate NullPointerException from our code)
  • Nice interoperability with Java
  • Officially supported language in Android Studio

You can watch Introduction to Kotlin - Google I/O ‘17 to have a better understanding of Kotlin’s appeal.

Learning Kotlin the fast way

Before we begin, we do need learn a little bit about Kotlin. The official Kotlin reference is the best place to start. Since it could be tiring to go through everything at one go, I selectively pickup:

The above should be enough to get you going, while I google on the go if I see some syntax which I didn’t understand.

Architecture Components

Why use Architecture Components?

  • Lifecycle-aware components to reduce leaks and crashes.
  • LiveData - UI code subscribe/listen to data changes and render UI accordingly (like Reactive programming in RxJava/React/Vue.js, with additional benifit of lifecyle-aware - stop update when pause or destroyed, auto cleanup)
  • ViewModel - Data logic/state which survice screen rotation
  • Room - ORM which return LiveData (notify when data changed) or RxJava

Learning Architecture Components the correct way

I make the mistake of going into tutorials directly as I am lazy to go through the documentation and thought that I could learn faster from sample code. Boy I was wrong as many tutorials focus on some very genric sample which fail to show production use case and highlight the benefit of using architecture components.

I would recommend reading Guide to App Architecture to have a basic understanding of the components and their relationship.

  • Room is the DataSource from SQLite. An additional layer of Repository is created if there are multiple DataSource (SQLite, Network, MemoryCache, etc). To avoid over engineering in the beginning, I would recommend use Room without Repository to keep things simple.
  • ViewModel is the data logic, which intereact with Room to retreive or update date . ViewModel supply LiveData (e.g. generated by Room) to Activity/Fragment. Activity/Fragment call ViewModel to update and retrieve data. ViewModel also store the state of Activity/Fragment. ViewModel shall never hold any UI widgets to avoid leaks and crashes.
  • Activity/Fragment subscribe to LiveData supplied by ViewModel to listen to data changes and render the UI. Activity/Fragment should only have UI logic, with state/data logic handled by ViewModel (Activity/Fragment call ViewModel methods).

Read ViewModels and LiveData: Patterns + AntiPatterns for a better understanding of each components, what to do and not to do.

Start Coding

Use Get Started with Kotlin on Android to create a Basic Activity project with Kotlin. Refer Adding Components to your Project to setup Architecture Components for Android Android.

NOTE: include kotlin-kapt plugin and replace annotationProcessor with kapt

Sequence of learning

Sample Code

Focus on MVVM architecture since we are using ViewModel

  • Two main source of sample codes are android-architecture-components and android-architecture.
  • I would recommend starting with BasicRxJavaKotlinSample since it’s relatively simple to understand. (NOTE: download the entire project by clicking on Clone or download and open in Android Studio for easier reading.)
  • Once you have a basic understanding on how to use the components, download dev-todo-mvvm-live-kotlin. This example is more complete (also more complex) which provide hint on directory structure and architecture design, but it doesn’t use LiveData for records from database.

NOTE: dev-todo-mvvm-live-kotlin make use of DataBinding where you can see both LiveData/SingleLiveEvent and Observable in ViewModel. DataBinding with LiveData shall be available in Android Studio 3.1 (currently in Beta, or you can use android-gradle 3.1).

FAQ / Tips

Why use Room (vs DBFlow) as ORM?

I have considered using DBFlow (speed, more established, good kotlin support). The main reason I choose Room is LiveData (play well with Architecture Component as a lifecycle-aware component, ability to subscribe to data changes).

Room is pretty nice to use as it’s something similar to Retrofit, where you can declare SQL statement and it will be generated with as function which return objects. Besides, it can return LiveData, RxJava or DataBinding Observarable.

@Dao
public interface UserDao {
    @Query("SELECT * FROM user")
    List<User> getAll();

    @Query("SELECT * FROM user WHERE id IN :userId")
    User getById(int userId);
}

LiveData is more than Database Object

LiveData is like a subset of RxJava, where you can subscribe to it and listen to changes. The most common use case is using Room to return LiveData.

LiveData also can be use as Event Bus, where I can create editEvent in ViewModel. Activity/Fragment can listen to editEvent to launch an activity, where the event is triggered in RecyclerViewAdapter though viewItem.holder.itemView.setOnClickListener.

NOTE: Since LiveData+ViewModel is lifecycle aware, I believe it is not possible to use it as Event Bus between activity (only one activity is active at anytime), though you can share data between fragments.

NOTE: Though RxJava could accomplished the same thing, but LiveData should be more lightweight with the benifit of being lifecycle-aware. Read about when to use RxJava in Architecture Components.

NOTE: use SingleLiveEvent which inherit from MutableLiveData. This avoids a common problem with events: on configuration change (like rotation) an update can be emitted if the observer is active. This LiveData only calls the observable if there's an explicit call to setValue() or call().

// In ViewModel
val editEvent = SingleLiveEvent<Long>()

// Listener in Activity/Fragment
viewModel.editEvent.observe(this@MainActivity, Observer<Long> { id ->
  startActivityForResult(UserActivity.newIntent(this@MainActivity, id), REQUEST_USER_ACTIVITY)
})

// Trigger event in RecyclerViewAdapter
val item = items.get(position)

holder.itemView.setOnClickListener {
    viewModel.editEvent.value = item.id
}

Another example would be to create a snackbarMessageEvent. Activity/Fragment will subscribe to this event to display snackbar if event is fired. Both UI or ViewModel code can display SnackBar by snackbarMessageEvent.value = "Edit successful".

Concern for Over-engineering

When implementing Architecture Components and looking into sample code of dev-todo-mvvm-live-kotlin, I realize it has a tendency to fall into the trap of over-engineering.

If you are building a simple app, it is possible to cut down a few layer of encapsulation (Activity + ViewModel + Room). If you are building a relatively large app, perhaps the encapsulation and seperation of code will bring more structure and maintainability, hopefully not at too much expense of productivity (Imagine we need at least 5 classes/files for a single activity: Activity + Fragment + Adapter + ViewModel + Respository + Room + Retrofit).

This work is licensed under a
Creative Commons Attribution-NonCommercial 4.0 International License.