【问题标题】:How to handle multiple possible response types with Retrofit2, Gson and Rx如何使用 Retrofit2、Gson 和 Rx 处理多种可能的响应类型
【发布时间】:2017-01-17 09:12:44
【问题描述】:

我必须使用的 API 很糟糕,总是返回 HTTP 200。但有时会有正确的响应:

[{"blah": "blah"}, {"blah": "blah"}]

有时会出现错误:

{"error": "Something went wrong", "code": 123}

我正在使用带有 Gson 转换器和 Rx 适配器的 Retrofit2:

final Api api = new Retrofit.Builder()
        .baseUrl(URL)
        .client(client)
        .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
        .addConverterFactory(GsonConverterFactory.create())
        .build()
        .create(Api.class);

现在,当我收到错误响应时,将调用 onError 处理程序,但出现以下异常:

java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
    at com.google.gson.stream.JsonReader.beginArray(JsonReader.java:350)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:80)
    at com.google.gson.internal.bind.CollectionTypeAdapterFactory$Adapter.read(CollectionTypeAdapterFactory.java:61)
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:37)
    at retrofit2.converter.gson.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:25)
    at retrofit2.ServiceMethod.toResponse(ServiceMethod.java:117)
    at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:211)
    at retrofit2.OkHttpCall.execute(OkHttpCall.java:174)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$RequestArbiter.request(RxJavaCallAdapterFactory.java:171)
    at rx.internal.operators.OperatorSubscribeOn$1$1$1.request(OperatorSubscribeOn.java:80)
    at rx.Subscriber.setProducer(Subscriber.java:211)
    at rx.internal.operators.OperatorSubscribeOn$1$1.setProducer(OperatorSubscribeOn.java:76)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:152)
    at retrofit2.adapter.rxjava.RxJavaCallAdapterFactory$CallOnSubscribe.call(RxJavaCallAdapterFactory.java:138)
    at rx.Observable.unsafeSubscribe(Observable.java:10144)
    at rx.internal.operators.OperatorSubscribeOn$1.call(OperatorSubscribeOn.java:94)
    at rx.internal.schedulers.CachedThreadScheduler$EventLoopWorker$1.call(CachedThreadScheduler.java:230)
    at rx.internal.schedulers.ScheduledAction.run(ScheduledAction.java:55)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428)
    at java.util.concurrent.FutureTask.run(FutureTask.java:237)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607)
    at java.lang.Thread.run(Thread.java:761)

我该如何解决?如果我能在onError 处理程序中得到响应,我可以用适当的错误模型类重新解析它。但似乎我无法得到原始响应。

【问题讨论】:

    标签: retrofit2


    【解决方案1】:

    您可以使用自定义 Gson 反序列化器将两个响应编组为单个对象类型。这是一个粗略的想法,假设您当前的响应类型是List<Map<String, String>>,您需要根据您的实际返回类型进行调整。我还假设 API 总是在成功时返回一个数组——

    public class MyResponse {
      String error;
      Integer code;
      List<Map<String, String>> response;
    }
    
    interface MyApi {
      @GET("/")
      Observable<MyResponse> myCall();
    }
    
    private class MyResponseDeserializer implements JsonDeserializer<MyResponse> {
      public MyResponse deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
          throws JsonParseException {
        MyResponse response = new MyResponse();
        if (json.isJsonArray()) {
          // It is an array, parse the data
          Type responseType = new TypeToken<List<Map<String, String>>>(){}.getType();
          response.response = context.deserialize(json, responseType);
        } else {
          // Not an array, parse out the error info
          JsonObject object = json.getAsJsonObject();
          response.code = object.getAsJsonPrimitive("code").getAsInt();
          response.error = object.getAsJsonPrimitive("error").getAsString();
        }
        return response;
      }
    }
    

    使用上述创建自定义Gson

    Gson gson = new GsonBuilder()
        .registerTypeAdapter(MyResponse.class, new MyResponseDeserializer())
        .create();
    

    在您的改造构建器中使用它 --

    .addConverterFactory(GsonConverterFactory.create(gson))
    

    您还应该更新您的界面以返回Observable&lt;MyResponse&gt;。您现在将在onNext 中获得成功和错误。您需要检查对象以确定它是否是成功响应 (response != null)。

    【讨论】:

    • 在 Observable 中获取错误,即 'java.lang.IllegalArgumentException: Unable to create call adapter for android.database.Observable'
    • @SAndroidDI 看起来您正在导入数据库 Observable 而不是 rx。
    猜你喜欢
    • 1970-01-01
    • 2018-02-16
    • 2020-05-12
    • 2020-07-15
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 2017-10-27
    • 1970-01-01
    相关资源
    最近更新 更多