Android Architecture Components — A Complete Kotlin Walkthrough

Ashwin S
AndroidPub
Published in
5 min readApr 15, 2018

A building without a proper plan is a ruin

The same applies to your code base if any particular pattern is not followed during development. A good pattern helps you with a testable, maintainable and robust code. We developers usually have our own style and pattern of development. And for those newbies in the wilderness, there are some popular suggested patterns to adopt to such as the MVC, MVP, MVVM etc., Now Google came out with its own life cycle aware pattern which goes by the name Android Architecture Components.

It eases,

  1. Managing lifecycle
  2. Persisting data locally
  3. Loading of data on need

Now what if I say that the Kotlin delegated properties, coroutines and classes are going to architect this project with less boiler plate and better performance. I will take you through that without further delay.

To make it much easier for a start, here are the list of dependancies to start with 😃

First the database !

First we create an abstract database class for our application to persist data locally and we are going to present it as an instance from the Room Database builder through the Kotlin Companions. Note that the Instance initialisation is locked by a synchronous block to avoid a data race.

We will just have one table called User and this referenced class can be defined using a Kotlin Data Class as,

It is a simple User data table with the @Entity annotation defining the table structure and @PrimaryKey with autoGenerate parameter to create a auto increment primary field. Remember to initialise it though !

The DAOs and the ViewModels !

Now with the creation of the database and table behind us, we need to focus on the other CRUD operations (read insert, update and delete). Well, fear not because extracting data and absorbing them into lists or objects starts with a simple declaration of a @Dao annotated interface with functions annotated with @Insert , @Query and @Delete annotations for respective operations.

The ViewModel class accesses the database and performs the data operations and provide the UI with the necessary data thereby providing complete abstraction from UI orientation changes and memory leak problems. It handles itself pretty well being life cycle aware. Just extend the ViewModel class from the Architecture Components and the rest is as simple as the below code.

Remember that we need to pass application instance to the view model to access the Database and the ViewModelProviders would fail to identify a ViewModel with a custom constructor parameter so do construct this factory to create and return this ViewModel instance to the provider.

We provide a lazy initialisation for the View Model so that it gets initialised after the first call of its instance and is available throughout the activity class outside the onCreate() method and this is because we cannot initialise the View Model before the activity onCreate() is called.

private val userViewModel: UserViewModel by lazy {
ViewModelProviders.of(this, ViewModelFactory(this.application)).get(UserViewModel::class.java)
}

Edit:

You can extend AndroidViewModel class instead which lets you pass application by default. And the ViewModel can be called directly in your activity as

private val userViewModel: UserViewModel by lazy {
ViewModelProviders.of(this).get(UserViewModel::class.java)
}

Activity time !!!

This architecture preaches data insertion, access and deletion on a worker thread instead of a UI thread to avoid UI freeze and ANRs. Though we can call .allowMainThreadQueries() to the database instance builder class, it is not recommended for a clean architecture. And we know that things can go a lot asynchronous here with the Threads coming in. Though the thread holds good enough for most of the cases, there is this question of OS dependancy, weight and possible blocking in efficient performance.

Here comes the Kotlin Coroutines! The tasks look seamlessly synchronised as it enables us to write non blocking asynchronous code. To put it in short, it is a light weighted OS independent thread. Now insertion or access is as simple as,

We can use this same launch function instead of the usual runOnUIThread to perform instant UI operations after the thread is done with the data access.

This UI is a custom coroutine context to be run in the UI thread and it is implemented here as per the official Kotlin examples.

There is this trouble of updating the adapter whenever the data in the list changes. Well lets make the UI reactive to that change with the Live Data from the components !

All you need to do is wrap a live data around the list returned from the DAO and then call observe on the list and update the adapter inside the onChanged of the Observer which is fired for any data change in the existing list fetched.

But wait, the Live data observes changes only in the existing list and not the new insertions and it is a monotonous task to implement load per need in case of list display of large number of records.

Want to observe the new insertions and implement load per need ? Well I present to you the last part of this roller-coaster ride of an article.

The Paging Library from the components !

The Paging library helps to implement this load per demand and also lets us listen to the new insertions to the table.

Well the implementation is fairly simple.

  1. Wrap the list of data around a DataSource Factory for the PagedList.
@Query("SELECT * FROM User")
fun usersAll(): DataSource.Factory<Int, User>

2. Return the PagedList wrapped around live data to observe changes for new insertions. The config builder lets us decide the position at which a new fetch should start and the number of records to be fetched for each pass.

3. Create a paged adapter as follows,

We need to pass the DiffUtil callback to the PagedListAdapter to distinguish between the items present already in the list and the new items to be added to the list.

Use the let transformation to bind the particular User object to the single item UI.

And finally observe the changes on the main thread after the data is inserted and list is fetched.

The insertion happens in parallel in the launch block and once the pager list gets the initial set of values, the async returns a deferred of list type to observe on the changes. This way it appears as if the list is already fetched on start after data insertion but in reality data is fetched upon further pass after the eventual insertion of data takes place.

That’s it folks, this is how a clean architecture in Android should be implemented ! You can find the source for the project I used for the article in the below link.

Happy reading people !

--

--