您当前的位置: 首页 >  kotlin

蓝不蓝编程

暂无认证

  • 2浏览

    0关注

    706博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Unable to create call adapter for kotlinx.coroutines.Deferred

蓝不蓝编程 发布时间:2019-04-16 15:31:14 ,浏览量:2

背景

在使用Kotlin coroutines结合Retrofit获取网络数据时,出现如下报错:

2019-04-16 15:24:47.210 20471-20471/com.cxyzy.note E/RepoViewModel$getRepo: java.lang.IllegalArgumentException: Unable to create call adapter for kotlinx.coroutines.Deferred
        for method Api.repos
        at retrofit2.Utils.methodError(Utils.java:52)
        at retrofit2.HttpServiceMethod.createCallAdapter(HttpServiceMethod.java:60)
        at retrofit2.HttpServiceMethod.parseAnnotations(HttpServiceMethod.java:34)
        at retrofit2.ServiceMethod.parseAnnotations(ServiceMethod.java:36)
        at retrofit2.Retrofit.loadServiceMethod(Retrofit.java:168)
        at retrofit2.Retrofit$1.invoke(Retrofit.java:147)
        at java.lang.reflect.Proxy.invoke(Proxy.java:1006)
        at $Proxy1.repos(Unknown Source)

原关键代码:

  1. 构造Retrofit接口代码
Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .client(provideOkHttpClient(provideLoggingInterceptor()))
        .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
        .build()
        .create(Api::class.java)
  1. Api定义
interface Api {
    @GET("/users/{user}/repos")
    fun repos(@Path("user") user: String, @Query("page") page: Int, @Query("per_page") perPage: Int): Deferred
}
简介方案
  1. 增加CoroutineCallAdapterFactory
import kotlinx.coroutines.CompletableDeferred
import kotlinx.coroutines.Deferred
import retrofit2.*
import java.lang.reflect.ParameterizedType
import java.lang.reflect.Type

class CoroutineCallAdapterFactory private constructor() : CallAdapter.Factory() {
    companion object {
        @JvmStatic
        @JvmName("create")
        operator fun invoke() = CoroutineCallAdapterFactory()
    }

    override fun get(
            returnType: Type,
            annotations: Array,
            retrofit: Retrofit
    ): CallAdapter? {
        if (Deferred::class.java != getRawType(returnType)) {
            return null
        }
        if (returnType !is ParameterizedType) {
            throw IllegalStateException(
                    "Deferred return type must be parameterized as Deferred or Deferred")
        }
        val responseType = getParameterUpperBound(0, returnType)

        val rawDeferredType = getRawType(responseType)
        return if (rawDeferredType == Response::class.java) {
            if (responseType !is ParameterizedType) {
                throw IllegalStateException(
                        "Response must be parameterized as Response or Response")
            }
            ResponseCallAdapter(getParameterUpperBound(0, responseType))
        } else {
            BodyCallAdapter(responseType)
        }
    }

    private class BodyCallAdapter(
            private val responseType: Type
    ) : CallAdapter {

        override fun responseType() = responseType

        override fun adapt(call: Call): Deferred {
            val deferred = CompletableDeferred()

            deferred.invokeOnCompletion {
                if (deferred.isCancelled) {
                    call.cancel()
                }
            }

            call.enqueue(object : Callback {
                override fun onFailure(call: Call, t: Throwable) {
                    deferred.completeExceptionally(t)
                }

                override fun onResponse(call: Call, response: Response) {
                    if (response.isSuccessful) {
                        deferred.complete(response.body()!!)
                    } else {
                        deferred.completeExceptionally(HttpException(response))
                    }
                }
            })

            return deferred
        }
    }

    private class ResponseCallAdapter(
            private val responseType: Type
    ) : CallAdapter {

        override fun responseType() = responseType

        override fun adapt(call: Call): Deferred {
            val deferred = CompletableDeferred()

            deferred.invokeOnCompletion {
                if (deferred.isCancelled) {
                    call.cancel()
                }
            }

            call.enqueue(object : Callback {
                override fun onFailure(call: Call, t: Throwable) {
                    deferred.completeExceptionally(t)
                }

                override fun onResponse(call: Call, response: Response) {
                    deferred.complete(response)
                }
            })

            return deferred
        }
    }
}
  1. 修改构造Retrofit接口代码,增加callAdapterFactory:addCallAdapterFactory(CoroutineCallAdapterFactory())
Retrofit.Builder()
        .baseUrl("https://api.github.com")
        .client(provideOkHttpClient(provideLoggingInterceptor()))
        .addCallAdapterFactory(CoroutineCallAdapterFactory())
        .addConverterFactory(GsonConverterFactory.create(GsonBuilder().create()))
        .build()
        .create(Api::class.java)
关注
打赏
1639405877
查看更多评论
立即登录/注册

微信扫码登录

0.0400s