简体   繁体   English

Retrofit 多种响应类型

[英]Retrofit multiple response types

How can I use Retrofit2 to parse these two kinds of API responses?我如何使用 Retrofit2 来解析这两种 API 响应?

Ok response (HTTP 200):好的响应(HTTP 200):

{
    "data": {
        "foo": "bar"
    }
}

Error response (HTTP 200):错误响应(HTTP 200):

{
    "error": {
        "foo": "bar"
    }
}

I've read tons of SO questions and tutorials, but I don't know how to do that, I've tried:我已经阅读了大量 SO 问题和教程,但我不知道该怎么做,我试过:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapterFactory(new ItemTypeAdapterFactory());
Gson gson = gsonBuilder.create();

final Retrofit retrofit = new Retrofit.Builder()
        .client(getOkHttpClient())
        .baseUrl(Constants.API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

And this is my ItemTypeAdapterFactory:这是我的 ItemTypeAdapterFactory:

class ItemTypeAdapterFactory implements TypeAdapterFactory {

    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {

        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<T>() {

            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            public T read(JsonReader in) throws IOException {

                JsonElement jsonElement = elementAdapter.read(in);

                if (jsonElement.isJsonObject()) {
                    JsonObject jsonObject = jsonElement.getAsJsonObject();

                    // Data key
                    if (jsonObject.has(Constants.JSON_KEY_DATA)) {

                        JsonElement jsonData = jsonObject.get(Constants.JSON_KEY_DATA);

                        // Primitive
                        if (jsonData.isJsonPrimitive()) {
                            jsonElement = jsonData.getAsJsonPrimitive();
                        }
                        // JSON object
                        else if (jsonData.isJsonObject()) {
                            jsonElement = jsonData;
                        }
                        // JSON object array
                        else if (jsonData.isJsonArray()) {
                            jsonElement = jsonData.getAsJsonArray();
                        }
                    }
                }

                return delegate.fromJsonTree(jsonElement);
            }
        }.nullSafe();
    }
}

But now I don't know the type to be declared on retrofit2 interface, inside Call:但是现在我不知道要在 retrofit2 接口上声明的类型,在 Call 中:

@GET("login")
Call<?> login(@Query(Constants.API_PARAM_TOKEN) String token);

Could you please point me in the right direction?你能给我指出正确的方向吗?

In a similar case, I once used JsonObject as type, so your function will look like this:在类似的情况下,我曾经使用JsonObject作为类型,因此您的函数将如下所示:

@GET("login")
Call<?> login(@Query(Constants.API_PARAM_TOKEN) String token);

Next, when you make a retrofit call, you keep the response as a string.接下来,当您进行改造调用时,您将响应保留为字符串。 So, in your java code, do something like this:因此,在您的 Java 代码中,执行以下操作:

Call<JsonObject> call = RetrofitClient.getAPIService().login('YOUR_INPUT');
Data data = null;
Error error = null;
call.enqueue(new Callback<JsonObject>() {
            @Override
            public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if(response.isSuccessfull()){
  String jsonString = response.body().toString();
  if(jsonString.contains("data:")){
       data = new Gson().fromJson(jsonString,Data.class);
  }else{
      error = new Gson().fromJson(jsonString,Error.class);
  }
}
        }

Here, I have used Data and Error these 2 classes.在这里,我使用了DataError这两个类。 They are the POJOs.他们是 POJO。 So Data can look something like this:所以数据看起来像这样:

Data.java : Data.java

public class Data implements Serializable{
 @SerializedName("foo")
    @Expose
    private Foo foo; // Foo is your desired data type 

}

Same goes for Error . Error So depending on your rest of the code, make necessary changes.因此,根据您的其余代码,进行必要的更改。 Good luck.祝你好运。

I used to do something like this我曾经做过这样的事情
BaseResponse基础反应

public class BaseResponse<D,E>{
E error;
D data;
public boolean isSuccess(){
    return error==null;
}

} }

Retrofit interface Retrofit接口

@GET("login")
Call<BaseResponse<LoginData,ErrorData>> login(@Query(Constants.API_PARAM_TOKEN) String token);

this approach will work OK when you have control over the REST API structure.当您控制 REST API 结构时,此方法可以正常工作。
the only problem is that you need to check for success using isSuccess method for every request before using the data object.唯一的问题是在使用数据 object 之前,您需要为每个请求使用 isSuccess 方法检查是否成功。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM