Android Architecture Components : Kotlin Coroutines inside NetworkBoundResource
Prerequisites : Before reading this post, I suggest you to catch up with these fundamentals topics :
- Android Architecture Components : as Lifecycle-aware components, LiveData, ViewModel
- Kotlin Coroutines : Google shared a nice codelabs on how to implement it in an Android app
- And this developer guide talking about app architecture.
… and, if you like, have some practice 😉
After I read the guide talking about app architecture combined with Android Architecture Components, I started to adopt the same principle in some projects and I decided to throw away my old fashioned habit of putting too many code into my Activity class (yes shame on me 😅) in the app. The guide explains very well how we must implement our app into different components to respect separation of concerns and the single source of truth concept, even if the app has his data from the Network and/or from local database.
One of these components that I liked is the abstract class NetworkBoundResource
. You will find an explanation of its utility in the guide’s last section. Generally, the purpose is to have a process flow on when app should fetch fresh data from Network or local data is sufficient to show on the UI.
After understanding how Google’s developers implemented it, I decided to :
- migrate the background task’s implementation from Java’s executor util to amazing Kotlin coroutines
- change the way of exposing data and its related loading/error status
Two useful classes are used in the Google’s developer implementation :
- Resource : for exposing data with status like success, loading and error
- AppExecutors : backed by Java’s Executor
java.util.concurrent.Executor
for making background task outside of the UI context.
The problem I found with the Resource
class implementation is that I can not emit the loading status without setting the data. Or by emitting the same data with a different loading status, the UI context risks to repeat the same process of showing data even if no changes occurred. I don’t like that. As a workaround, I created a new class named LiveResource
:
With this class and the Kotlin Coroutines feature, the new NetworkBoundResource
looks as the following snippet :
What did I change here ?
- the
result
member is not aMediatorLiveData<Resource<ResultType>>
anymore but becomes aMutableLiveData
. There are alsoLiveData
for the loading state and the error which can occurred. And a coroutineJob
member is added instead of theAppExecutor
passed to theNetworkBoundResource
constructor :
- In the init block, an instance of
CoroutineScope
is created and launched in the IO context as background task to get the data from Network and/or local database. - Some functions like
fetchFromNetwork
loadFromDb
, etc became asuspend
functions to support Coroutines non-blocking operations and the result type is notLiveData
anymore.
You can notice with this new implementation that it can now emit different status of the data loading process without the concerned data necessarily.
Before :
After :
How to use it in a UserRepository
?
Notes : If you don’t want to expose UserEntity
to the UI, you can map it to another object like UserUIModel
:
The ViewModel
that uses this repository can have the following implementation :
And finally, LiveData’s Observer
s are attached in the fragment onActivityCreated
(or in the activity onCreate
) to display to the user :
By separating the data result, the loading status and the error in different LiveData
, you now have the opportunity to ignore easily one of them. For example, only data result is important so no need to observe loading status and error.
Notes : In the snippets above, the service which executes web api call and the DAO for local data access are not detailed here. However, I will use Retrofit (with coroutines support plugin) and Room, respectively, to fulfill these functionalities.
That’s all ! Feel free to share and comment.