Retrofit自定义CallAdapter返回Flow<DataState<T>>时,如何让Moshi仅解析泛型T?
问题根因
崩溃的核心原因是你自定义CallAdapter的responseType返回值错误:你当前应该是返回了DataState<T>类型,Retrofit会将该类型传给序列化转换器做解析,Moshi找不到DataState对应的适配器就抛出了异常。
你预期的逻辑是Moshi只解析最内层的T,外层DataState由CallAdapter自行封装,所以需要调整CallAdapter的类型提取逻辑。
修复步骤
1. 调整CallAdapter.Factory的泛型提取逻辑
在Factory的get方法中需要提取两层泛型:首先提取Flow的泛型参数得到DataState<T>,再提取DataState的泛型参数得到最内层的T,将T作为实际要解析的类型传给自定义CallAdapter。
示例代码:
class FlowDataStateCallAdapterFactory : CallAdapter.Factory() { override fun get( returnType: Type, annotations: Array<out Annotation>, retrofit: Retrofit ): CallAdapter<*, *>? { // 校验返回值原始类型是否为Flow if (getRawType(returnType) != Flow::class.java) return null // 提取Flow的泛型参数,即DataState<T> val dataStateType = getParameterUpperBound(0, returnType as ParameterizedType) if (getRawType(dataStateType) != DataState::class.java) return null // 提取DataState的内层泛型T,该类型就是Moshi需要解析的实体类型 val innerDataType = getParameterUpperBound(0, dataStateType as ParameterizedType) return FlowDataStateCallAdapter<Any>(innerDataType) } }
2. 修改自定义CallAdapter实现
CallAdapter的responseType直接返回从Factory传入的内层T类型,Retrofit会自动让Moshi只解析该类型,你只需要在adapt方法中将解析完成的T封装为DataState再包装为Flow返回即可。
示例代码:
class FlowDataStateCallAdapter<T>( private val targetType: Type ) : CallAdapter<T, Flow<DataState<T>>> { // 直接返回内层T的类型,告知Retrofit只需要让Converter解析该类型 override fun responseType(): Type = targetType override fun adapt(call: Call<T>): Flow<DataState<T>> { return callbackFlow { call.enqueue(object : Callback<T> { override fun onResponse(call: Call<T>, response: Response<T>) { if (response.isSuccessful) { val body = response.body() if (body != null) { trySend(DataState(body, State.SUCCESS)) } else { trySend(DataState(null, State.EMPTY)) } } else { trySend(DataState(null, State.HTTP_ERROR)) } close() } override fun onFailure(call: Call<T>, t: Throwable) { trySend(DataState(null, State.NETWORK_ERROR)) close(t) } }) awaitClose { call.cancel() } } } }
3. 注册自定义CallAdapterFactory
构造Retrofit实例时,将自定义Factory添加到CallAdapter列表中即可:
val retrofit = Retrofit.Builder() .baseUrl(你的接口域名) .addCallAdapterFactory(FlowDataStateCallAdapterFactory()) // 如有其他普通Flow接口需求,可以继续添加官方协程CallAdapter // .addCallAdapterFactory(CoroutineCallAdapterFactory.create()) .addConverterFactory(MoshiConverterFactory.create(你的Moshi实例)) .build()
内容的提问来源于stack exchange,提问作者Budius
相关产品推荐
相关产品推荐

