Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrofit 2.6.0: Custom Coroutines CallAdapterFactory

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

enter image description here

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
        }

    }
}
like image 749
Leonardo Deleon Avatar asked Aug 23 '19 11:08

Leonardo Deleon


People also ask

Can I use retrofit with coroutines?

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

What is the use of retrofit calladapter?

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.

How do I delegate call responses in retrofit?

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.

How to get a method from a custom calladapter?

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.


1 Answers

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?.

like image 143
Valeriy Katkov Avatar answered Oct 24 '22 11:10

Valeriy Katkov