I need to do custom error handling in my api and I wanted to use coroutines with the new version of Retrofit. Since we don't have to use Deferred
any longer, our own Jake Wharton wrote this on reddit a month ago
https://github.com/square/retrofit/blob/master/samples/src/main/java/com/example/retrofit/RxJavaObserveOnMainThread.java
But I'm having problems creating the CallAdapterFactory
properly.
To be specific, I don't understand: "Delegates to built-in factory and then wraps the value in sealed class"
Is there anyone already using this setup that can help?
Here's the current code
sealed class Results<out T: Any> {
class Success<out T: Any>(val response: T): Results<T>()
class Failure(val message: String, val serverError: ServerError?): Results<Nothing>()
object NetworkError: Results<Nothing>()
}
class ResultsCallAdapterFactory private constructor() : CallAdapter.Factory() {
companion object {
@JvmStatic
fun create() = ResultsCallAdapterFactory()
}
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
return try {
val enclosedType = returnType as ParameterizedType
val responseType = getParameterUpperBound(0, enclosedType)
val rawResultType = getRawType(responseType)
val delegate: CallAdapter<Any,Any> = retrofit.nextCallAdapter(this,returnType,annotations) as CallAdapter<Any,Any>
if(rawResultType != Results::class.java)
null
else {
object: CallAdapter<Any,Any>{
override fun adapt(call: Call<Any>): Any {
val response = delegate.adapt(call)
//What should happen here?
return response
}
override fun responseType(): Type {
return delegate.responseType()
}
}
}
} catch (e: ClassCastException) {
null
}
}
}
But since Retrofit supports the suspend modifier on functions for Kotlin now, we don’t have to do this anymore. So now using Retrofit with Coroutines is as simple as this
The Retrofit CallAdapter handles Retrofit responses and exceptions, so the responsibility of the data layer has been significantly reduced. Each layer can expect the result type of the Retrofit API call to be NetworkResult, so you can write useful extensions for the NetworkResult class.
One of the best ways is by building a custom Retrofit CallAdapter, which allows you to delegate call responses; you can also return a preferred type in the Retrofit side as seen in the figure below: Let’s see how to implement and adopt a custom Retrofit CallAdapter step by step.
get method in the CallAdapter.Factory should return a callback adapter for interface methods that it could handle or null if it’s can’t be handled by this factory. So simply our get method in our custom CallAdapter.Factory should check if the returnType is our sealed class for the API response calls, and then handle it.
I've created an example of such a factory, you can find it here on GitHub. Also take a look at a similar question: How to create a call adapter for suspending functions in Retrofit?.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With