我需要创建一个可处理此类网络呼叫的改造呼叫适配器:
@GET("user")
suspend fun getUser(): MyResponseWrapper<User>
我希望它不使用Kotlin Coroutines Deferred
。我已经有了使用的成功实现Deferred
,它可以处理以下方法:
@GET("user")
fun getUser(): Deferred<MyResponseWrapper<User>>
但是我希望能够使函数成为挂起函数并删除Deferred
包装器。
使用暂停功能,Retrofit的工作方式就像Call
在返回类型周围有包装器一样,因此suspend fun getUser(): User
被视为fun getUser(): Call<User>
我试图创建一个呼叫适配器来尝试解决这个问题。到目前为止,这是我的实现:
厂
class MyWrapperAdapterFactory : CallAdapter.Factory() {
override fun get(returnType: Type, annotations: Array<Annotation>, retrofit: Retrofit): CallAdapter<*, *>? {
val rawType = getRawType(returnType)
if (rawType == Call::class.java) {
returnType as? ParameterizedType
?: throw IllegalStateException("$returnType must be parameterized")
val containerType = getParameterUpperBound(0, returnType)
if (getRawType(containerType) != MyWrapper::class.java) {
return null
}
containerType as? ParameterizedType
?: throw IllegalStateException("MyWrapper must be parameterized")
val successBodyType = getParameterUpperBound(0, containerType)
val errorBodyType = getParameterUpperBound(1, containerType)
val errorBodyConverter = retrofit.nextResponseBodyConverter<Any>(
null,
errorBodyType,
annotations
)
return MyWrapperAdapter<Any, Any>(successBodyType, errorBodyConverter)
}
return null
}
适配器
class MyWrapperAdapter<T : Any>(
private val successBodyType: Type
) : CallAdapter<T, MyWrapper<T>> {
override fun adapt(call: Call<T>): MyWrapper<T> {
return try {
call.execute().toMyWrapper<T>()
} catch (e: IOException) {
e.toNetworkErrorWrapper()
}
}
override fun responseType(): Type = successBodyType
}
runBlocking {
val user: MyWrapper<User> = service.getUser()
}
使用此实现,一切都会按预期工作,但是在将网络调用的结果传递给user
变量之前,我收到以下错误:
java.lang.ClassCastException: com.myproject.MyWrapper cannot be cast to retrofit2.Call
at retrofit2.HttpServiceMethod$SuspendForBody.adapt(HttpServiceMethod.java:185)
at retrofit2.HttpServiceMethod.invoke(HttpServiceMethod.java:132)
at retrofit2.Retrofit$1.invoke(Retrofit.java:149)
at com.sun.proxy.$Proxy6.getText(Unknown Source)
...
从Retrofit的源代码开始,以下是这段代码HttpServiceMethod.java:185
:
@Override protected Object adapt(Call<ResponseT> call, Object[] args) {
call = callAdapter.adapt(call); // ERROR OCCURS HERE
//noinspection unchecked Checked by reflection inside RequestFactory.
Continuation<ResponseT> continuation = (Continuation<ResponseT>) args[args.length - 1];
return isNullable
? KotlinExtensions.awaitNullable(call, continuation)
: KotlinExtensions.await(call, continuation);
}
我不确定如何处理此错误。有没有办法解决?
这是适配器的一个工作示例,该适配器自动将响应Result
包装到包装器中。GitHub示例也可用。
// build.gradle
...
dependencies {
implementation 'com.squareup.retrofit2:retrofit:2.6.1'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation 'com.google.code.gson:gson:2.8.5'
}
// test.kt
...
sealed class Result<out T> {
data class Success<T>(val data: T?) : Result<T>()
data class Failure(val statusCode: Int?) : Result<Nothing>()
object NetworkError : Result<Nothing>()
}
data class Bar(
@SerializedName("foo")
val foo: String
)
interface Service {
@GET("bar")
suspend fun getBar(): Result<Bar>
@GET("bars")
suspend fun getBars(): Result<List<Bar>>
}
abstract class CallDelegate<TIn, TOut>(
protected val proxy: Call<TIn>
) : Call<TOut> {
override fun execute(): Response<TOut> = throw NotImplementedError()
override final fun enqueue(callback: Callback<TOut>) = enqueueImpl(callback)
override final fun clone(): Call<TOut> = cloneImpl()
override fun cancel() = proxy.cancel()
override fun request(): Request = proxy.request()
override fun isExecuted() = proxy.isExecuted
override fun isCanceled() = proxy.isCanceled
abstract fun enqueueImpl(callback: Callback<TOut>)
abstract fun cloneImpl(): Call<TOut>
}
class ResultCall<T>(proxy: Call<T>) : CallDelegate<T, Result<T>>(proxy) {
override fun enqueueImpl(callback: Callback<Result<T>>) = proxy.enqueue(object: Callback<T> {
override fun onResponse(call: Call<T>, response: Response<T>) {
val code = response.code()
val result = if (code in 200 until 300) {
val body = response.body()
Result.Success(body)
} else {
Result.Failure(code)
}
callback.onResponse(this@ResultCall, Response.success(result))
}
override fun onFailure(call: Call<T>, t: Throwable) {
val result = if (t is IOException) {
Result.NetworkError
} else {
Result.Failure(null)
}
callback.onResponse(this@ResultCall, Response.success(result))
}
})
override fun cloneImpl() = ResultCall(proxy.clone())
}
class ResultAdapter(
private val type: Type
): CallAdapter<Type, Call<Result<Type>>> {
override fun responseType() = type
override fun adapt(call: Call<Type>): Call<Result<Type>> = ResultCall(call)
}
class MyCallAdapterFactory : CallAdapter.Factory() {
override fun get(
returnType: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
) = when (getRawType(returnType)) {
Call::class.java -> {
val callType = getParameterUpperBound(0, returnType as ParameterizedType)
when (getRawType(callType)) {
Result::class.java -> {
val resultType = getParameterUpperBound(0, callType as ParameterizedType)
ResultAdapter(resultType)
}
else -> null
}
}
else -> null
}
}
/**
* A Mock interceptor that returns a test data
*/
class MockInterceptor : Interceptor {
override fun intercept(chain: Interceptor.Chain): okhttp3.Response {
val response = when (chain.request().url().encodedPath()) {
"/bar" -> """{"foo":"baz"}"""
"/bars" -> """[{"foo":"baz1"},{"foo":"baz2"}]"""
else -> throw Error("unknown request")
}
val mediaType = MediaType.parse("application/json")
val responseBody = ResponseBody.create(mediaType, response)
return okhttp3.Response.Builder()
.protocol(Protocol.HTTP_1_0)
.request(chain.request())
.code(200)
.message("")
.body(responseBody)
.build()
}
}
suspend fun test() {
val mockInterceptor = MockInterceptor()
val mockClient = OkHttpClient.Builder()
.addInterceptor(mockInterceptor)
.build()
val retrofit = Retrofit.Builder()
.baseUrl("https://mock.com/")
.client(mockClient)
.addCallAdapterFactory(MyCallAdapterFactory())
.addConverterFactory(GsonConverterFactory.create())
.build()
val service = retrofit.create(Service::class.java)
val bar = service.getBar()
val bars = service.getBars()
...
}
...
问题内容: 我正在使用SimpleXml改造2.0.0-beta1。我想从REST服务中检索简单(XML)资源。使用SimpleXML编组/解组Simple对象可以正常工作。 使用此代码(转换为2.0.0之前的代码)时: 服务: 我得到这个异常: 我想念什么?我知道用作品包装返回类型。但是我希望服务将业务对象作为类型返回(并在同步模式下工作)。 更新 添加了额外的依赖关系并根据不同的答案提出建议后
问题内容: 我正在尝试使用rxJava,rxAndroid,Retrofit2和OkHTTP3从URL端点下载文件。我的代码无法为“ Observable <retrofit2.Response <okhttp3.ResponseBody ”创建呼叫适配器。这些方法对我来说是陌生的,因此我认为这里缺少一个重要的概念。任何方向或点将不胜感激。 的android.view.View.performCl
我试图在AnyLogic中模拟一个有限呼叫人口模型。我的群体由10个代理组成,我希望他们在得到服务后返回到源节点。 我考虑过使用SelectOutput节点进行调节,但Source节点没有任何输入。我想出的最好的办法是将到达的客户数量限制为10个。但是,在这种情况下,模型在10次到达后停止运行,这不是一个合适的结果。 我该怎么做才能在AnyLogic中模拟这种类型的模型? 编辑:我认为让代理返回到
改型异步请求是用两个方法onResponse()和onFailure()回调的。 我还想使用Gson转换器来转换改型响应,然后用APIPesponse包装它。 如果我用like 好像不起作用。不能将json响应数据解析到结果对象中。 有人能帮助如何让用调用enqueue吗?结果是使用Gson转换器解析json数据内容。 有人能帮我指出这个问题吗?
SubRoutine 是指、在剧本中的某处「呼叫」其他剧本段落的功能。SubRoutine呼叫出的剧本段落在执行完后、就会返回原来的剧本。 这和宏(Macro) ( → 宏(Macro)的使用 ) 的功能类似、但 SubRoutine 一般用于执行比较复杂的操作、而 Macro 则相对简单一些。(例如, Macro 中禁止使用标签) SubRoutine 的基本使用方法 SubRoutine
1、接口声明 如果您希望在自己的CRM系统嵌入呼叫中心能力,需要对接智齿呼叫中心能力,在对接前请您阅读如下对接流程,以便您更好的完成对接。如果只对接基本呼叫能力,预计对接及调试过程1周左右即可完成。 第一步:获取第三方用户接口调用唯一凭证 请联系您的售后经理,获取您企业的如下信息: 1、companyid(企业id) 2、appid(第三方用户接口调用唯一凭证id) 3、app_key(第三方用户