ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Follow publication

Android Architecture starring Kotlin Coroutines, Jetpack (MVVM, Room, Paging), Retrofit and Dagger 2

Over years Android architecture evolved to support complex, robust, production-quality apps on any scale. It is great to see how Google recommendations are aligned with Android community needs and choices. In the last years Google has promoted Kotlin as first class citizen, introduced Guide to app architecture starring uncle’s Bob Clean Architecture concept with MVVM presentation pattern. We have been given out of box architecture puzzles packed into Architecture Components and Android Jetpack. Retrofit, RxJava and Dagger have been taken into official tutorials.

Last, but not least Kotlin Coroutines have been landed at Google IO 2019. The inspiration comes from Reactive Programming (frameworks like RxJava). Kotlin Coroutines manage background threads with simplified code and reducing needs for callbacks.

Yet when it comes to combine all architecture puzzles together into simple client application it is difficult to find open sourced app sample to follow. One of the Infinity Stone always missing.

We are going to implement sample app starring Google Guide to app architecture (based on MVVM and Repository patterns), using Android Jetpack(ViewModel, LiveData, Room, Paging, Navigation), Retrofit and Dagger 2. App is entirely written in Kotlin. Special guest is Kotlin Coroutines which we will use instead of RxJava2 for basic use case of data loading.

We will implement app step by step mastering architecture concepts. Note: The goal of article is to give overview of Android Architecture current state combining all of components together into simple production-quality application. The article assumes familiarity of reader with concepts and library mentioned.

Lets dive into it!

The full source code of this project together with full list of libraries used can be found on GitHub:

The project we will develop

Every Android Engineer had or will have a need to write basic application from scratch. Either for new project, prototyping or interviewing. The classic application consists of 2 screens: infinity scrolling list of items and details view using network and persistency.

I am big fan of LEGO® mini figures and LEGO® in general, therefore I have chosen to write a simple catalog to browse sets. The app consists of 3 screens: list of themes, infinity list of sets and set details.

Architecture overview

Clean architecture assumes separation of concerns with UI(Activity, Fragment, View), Presentation(ViewModel) and Data(Repository) layers. ViewModel helps to handle user interaction, save current state of app and automatically manage Android UI components lifecycle via LiveData.

Repository serves as data point, where ViewModel knows nothing about source of data. It is up to repository to decide whether local or remote data should be given back to user. It serves well to handle data synchronisation conflicts.

Lets show list of LEGO® themes to user

Lets develop an application screen with list of themes. We will load a list of themes and show them to user. We will support offline mode and fetch data from REST API.

Model

User Interface and Experience

Lets start from writing a layout for fragment in fragment_themes.xml. Data binding is used to bind data to view in declarative style. View Binding as a part of Data Binding is used to have references of views in a fragment.

Then lets add list_item_theme.xml with item UI representation.

In order to display items in list and reuse view resources lets write LegoThemeAdapter.

Lets write a LegoThemeFragment with viewModel injected.

A Fragment starts observe a LiveData<Result<List<LegoTheme>>> themes from viewModel. Thats where magic begins. LiveData is lifecycle aware and observing data for any new changes.

Error and Loading states handling

Note that Fragment observes a LiveData of a Result object. It intends to provide feedback to UI, whether it should show Success, Loading or Error state. In case of Success we show loaded data, Loading will trigger progressBar appearance and Error will give feedback to user via Snackbar.

Dependency injection with Dagger 2

Dependency Injection and Dagger 2 is comprehensive topic to discuss in one article with architecture overview. But one case deserves an attention: injection of viewModel.

Since Fragment is initialised by Android SDK, we can not inject viewModel on construction phase. Therefore we will inject it via ViewModelFactory.

The full implementation of app dependancy graph can be found on Github.

Presentation with MVVM, LiveData and Lifecycles

Thankfully to ViewModel and LiveData lifecycle awareness our LegoThemeViewModel is very simple. It has only LegoThemeRepository as a dependency in order to provide data.

Repository with Kotlin Coroutines based on single source of truth strategy

In order to avoid synchronisation discrepancies it is required to define a single source of truth. The Repository serves as an abstract source of data for Presentation Layer (viewModel). Although Repository should decide which data source is truth. Lets define a local database as a source of truth. Whenever data is requested we will give back local copy, then we fetch remote data, save it to database, which will automatically notify Repository about new data available.

Lets look at data flow:

Here LiveData and Coroutines come to rescue and simplify code. Lets look at LegoThemeRepository.

We have got 2 dependencies: dao: LegoThemeDao and remoteSource: LegoThemeRemoteSource. Themes are received via Coroutines suspend functions in order to make this calls asynchronous and unblock main UI thread from work. Lets dive into our SingleSourceOfTruth.kt implementation in order to understand multithreading mechanism under the hood.

We are using extension function liveData() from CoroutineLiveData.kt class of LiveData library. liveData() function accepts Coroutine Dispatcher in order to choose running tread.

There are 4 types of Dispatchers:

  • Default (Designed for heavy computational work)
  • Main (Main thread operating with UI objects)
  • IO (Designed for offloading blocking IO tasks like network, database operations)
  • Unconfined (Not confined to any specific thread)

In our case Dispatchers.IO is exactly what we need. We use Coroutines suspend functions in order to fetch, load and save data. To communicate to UI with Success, Loading or Error state we use emit() function, which automatically notify observer on Main UI thread.

Persistency with Room and Kotlin Coroutines

Room database has built in support of LiveData and Kotlin Coroutines, which make multithreading easy task. Lets have a closer look at LegoTheme Entity and LegoThemeDao.

Network with Retrofit and Kotlin Coroutines

Retrofit has a built in support for Kotlin Coroutines functions too. For this just define your API end point methods with suspend keyword. Fetched data will be saved into database, it will trigger database to notify viewModel with liveData of updated information. Therefore we do not need to return liveData from Retrofit call directly.

In order to handle errors lets write BaseDataSource class, which takes Retrofit Response object and transform it either to Success or Error. This state will be communicated to UI eventually via Repository -> ViewModel -> Fragment.

Paging library

Since we accomplished screen with limited amount of Themes we can tackle screen with Sets, where we need to show infinity number of items. We want to load and display small chunks of data at a time. For this purpose lets use Paging library.

Good news that Room database support offline paging. It works like a charm in combination with Paging. A minimum amount of code need to written. All you need to do is to change your Dao class method from LiveData<List<T>> to DataSource.Factory<Int, T>.

Then using LivePagedListBuilder it can be converted to known LiveData which will be observed in viewModel.

For online Paging PageKeyedDataSource can be created, where API endpoints will be used in order to scroll pages forward and back.

Lets see LegoSetRepository with functions to observe paged data lists locally and remote.

Pros: Paging is easy to use for offline and online sources separately.
Cons:
- Error handling is not straightforward, it requires to make custom error callbacks;
- Paging requires non trivial customisation in order to implement Single Source of Truth strategy loading pages from database and load more items on a fly from server. Therefore for simplicity of this case study, current app uses separate online and offline paging. Repository choses local or remote paging depending on user available connectivity.

CoroutineWorker with Work Manager

Work Manager support Kotlin Coroutines via CoroutineWorker class. It does not provide async thread to run on by default like IntentService. So we need to use coroutineScope and withContext() function specifying working thread via chosen Dispatcher. Let look at SeedDatabaseWorker example which preloads database items on database create event.

Navigation component

Navigation component structures navigation and show all transitions in one diagram via xml. It is great to see all transition in one place having control over them. Library eliminates boilerplate code for fragment state managing. Two additional perks are default animations of screen transactions, parameter definition in place with fragment declaration.

Navigation component serves greatly for purpose of basic application. Although from experience with more complex applications, which uses BottomNavigationView and other navigation patters, things become not trivial and require customisation. So keep in mind scale of your application when you decide to use Navigation component.

I think within time and our community impact component will evolve into comprehensive solution.

Lets have a closer look at nav_main.xml.

Summary

That’s it! We have just completed an application using Kotlin Coroutines, Android Jetpack(ViewModel, LiveData, Room, Paging, Navigation), Retrofit and Dagger 2. Application is scalable and robust thankfully to designed Architecture based on Guide to app architecture.

We can see that Kotlin Coroutines in combination with Kotlin built in functions and LiveData support is a strong alternative to RxJava2. It eliminates callbacks and being less verbose, making code more concise. Also having less 3rd party dependencies is great benefit. Kotlin Coroutines serve great for basic application and have potential for big scale solutions.

I hope this Architecture Overview combined with all used components will boost your productivity and expertise!

I would like to see your opinion and experience with current Architecture and components below in comments.

In next article I would like to address Android Architecture decisions. How to not blindly follow newest trends, but pragmatically ponder pros and cons of every architecture decision we make. Stay tuned!

If you find this tutorial useful your Claps will be much appreciated and inspiring for the next articles!

The full source code of this project together with full list of libraries used can be found on GitHub:

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

Published in ProAndroidDev

The latest posts from Android Professionals and Google Developer Experts.

Written by Eli Fox

Engineering Leadership at Meta • Follow me for the weekly big tech career tips https://www.linkedin.com/in/elifox/

Responses (25)

Write a response