【问题标题】:Retrofit 2 handling dynamic api callbacks of either JSONArray or JSONObjectRetrofit 2 处理 JSONArray 或 JSONObject 的动态 api 回调
【发布时间】:2019-04-03 05:54:22
【问题描述】:

我的JSON 服务器响应通常是这样的[{}](对象数组),除了他们设置错误以返回对象{} 所以当我打电话时当然如果响应有问题并且它返回一个对象我得到以下错误:

Expected BEGIN_ARRAY but was BEGIN_OBJECT

在我的代码中,因为我期待一个 ArrayList 并获取一个对象(但我不确定如何处理这个问题?当我得到对象时,这意味着 API 调用存在问题,我需要处理对象中响应的内容。

来自 API 的示例错误响应:

{
  "StatusCode": -7,
  "StatusMessage": "Invalid",
  "Details": ""
}

APIService接口如下:

interface MyAPIService {
    @GET("RequestByToken")
    fun getCurrentRequestAsync(
        @Query("token") token: String
    ): Deferred<List<CurrentResponse>>

    companion object {
        operator fun invoke(
            connectivityInterceptor: ConnectivityInterceptor
        ): MyAPIService {
            val requestInterceptor = Interceptor { chain ->

                //Creates a new URL adding in the CONST'S
                val url = chain.request()
                    .url()
                    .newBuilder()
                    .addQueryParameter("format", FORMAT)
                    .build()

                //Creates new Request with the new URL
                val request = chain.request()
                    .newBuilder()
                    .url(url.toString())
                    .build()

                println(request)
                return@Interceptor chain.proceed(request)
            }

            //Intercepts each http call and adds the url above automatically
            val okHttpClient = OkHttpClient.Builder()
                .addInterceptor(requestInterceptor)
                .addInterceptor(connectivityInterceptor)
                .build()

            return Retrofit.Builder()
                .client(okHttpClient)
                .baseUrl(BASE_URL)
                .addCallAdapterFactory(CoroutineCallAdapterFactory())
                .addConverterFactory(GsonConverterFactory.create())
                .build()
                .create(MyAPIService::class.java)
        }
    }
}

【问题讨论】:

  • 尝试Deferred&lt;Any&gt; 而不是Deferred&lt;List&lt;CurrentResponse&gt;&gt; 它将接受所有模型响应检查 if(response.body is List){//这意味着它是你的数组} else { //这是错误的回应
  • 返回 Any 时遇到的问题是,当我需要使用 List 并将其设置为 List 时,它抱怨它无法从 LinkedTreeMap 转换它?
  • onFailure 方法中返回此错误

标签: android json api kotlin retrofit2


【解决方案1】:

您可以使用JsonElement 作为您的返回类型,并使用isJsonArray() 方法确定它是JsonObject 还是JsonArray,然后您可以从那里简单地反序列化它。

您也可以以一般方式执行此操作,并创建一个代表您的列表和对象响应的类,并为该类型编写一个类型适配器:

 sealed class SampleResponse {
    data class ArraySampleResponse(val currentResponses: List<CurrentResponse>) : SampleResponse()
    data class SimpleSampleResponse(val currentResponse: CurrentResponse) : SampleResponse()
}
class CustomDeserializer : JsonDeserializer<SampleResponse> {

    @Throws(JsonParseException::class)
    fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): SampleResponse {
        if (json.isJsonObject()) {
            // parse as object and create your object
            return SampleResponse.SimpleSampleResponse() 
        } else if (json.isJsonArray()) {
            // parse as array and create your object
            return SampleResponse.ArraySampleResponse()

        }
    }
}

【讨论】:

  • 我不完全理解你的回答。
  • 它所做的是,它为自定义类 (SampleResponse) 创建一个 decerializer - 这是您的 - 并且可以根据通过网络接收的数据创建该类。您可以将您的 API 声明为 Deferred&lt;SampleResponse&gt;,并将此序列化程序添加到 Gson,它将根据根 json 元素的内容 - 数组或对象 - (或您可能喜欢的任何其他条件)创建。您需要根据自己的喜好创建 SampleResponse 类,以便在使用列表或对象启动时具有多个字段。如果您需要更多帮助,请告诉我。
  • 非常有帮助,但是我在使用 Kotlin 时遇到了问题,这看起来像 Java 到目前为止我有这个 ``` class CustomDeserializer(): JsonDeserializer { override fun deserialize(json: JsonElement, typeOfT: Type, context: JsonDeserializationContext): SampleResponse { if (json.isJsonObject) { // 解析为对象并创建对象 } else if (json.isJsonArray) { // 解析为数组并创建对象 } } } ```
  • 你有什么问题?将上面的代码转换为 Kotlin 应该没有害处! :)
  • 我遇到的问题是它不知道 SampleResponse 是什么
猜你喜欢
  • 2020-03-13
  • 2021-05-19
  • 2023-03-20
  • 2015-11-26
  • 1970-01-01
  • 1970-01-01
  • 2014-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多