Using coroutine with exception handling instead of Retrofit Callbacks.
Coroutines Implementation Tips
Retrofit already has a library that integrates coroutines.
Add all the dependencies for coroutines:
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$version_kotlin_coroutines"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$version_kotlin_coroutines"
implementation "com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:$version_retrofit_coroutines_adapter"
Add CoroutineCallAdapterFactory to Retrofit builder.
.addCallAdapterFactory(CoroutineCallAdapterFactory())
this will enable Retrofit to produce a coroutine-based API. CallAdapters will add the ability for Retrofit to create an APIs that returns something other than the default call class. Here in our case the CoroutineCallAdapterFactory will allow us to replace a call and get properties with a coroutine deferred.
Deferred is a coroutine job that can directly return a result.
Coroutine job provides a way of canceling and determining the state of a coroutine.
Unlike a job, deferred has a method called await. Await is a suspend function on the deferred. It causes the code to await without blocking in true coroutine fashion until the value is ready and the value is returned.
It works like this with Retrofit : Retrofit will return a deferred and then you await the result which has the appearance of synchronous code. If there's an error await will return that by throwing an exception.
How do we change the code in our ViewModel to use the deferred instead of the Retrofit callback ?
Inside ViewModel we create a Coroutine Job ad Coroutine Scope using the Main Dispatcher.
Since Retrofit does all of its work on a background thread for us. there is no reason to use any other thread for our scope. This allows us to easily update the value of our MutableLiveData when we get a result.
In order to use our deferred we need to be inside of a coroutine scope.
We are still executing code in main thread but now we are letting coroutine manage concurrency.
Calling, a method from our ApiService class, creates and starts the network call in a background thread, returning the deferred.
Calling await in the deferred, returns the result from the network call when the value is ready.
Await is non blocking which means this will trigger our API service to retrieve the data from the network without blocking our current thread. Which is important because we're in the scope of the UI thread. Once it's done the code continues executing from where it left off.
Comments
Post a Comment