You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 05:36:02