在Retrofit 2中如何处理错误的不同模式?

时间:2019-05-06 19:20:55

标签: java android gson retrofit2

我有一个API,它返回以下模式之一:

成功(找到数据)

{
    item_count: 83,
    items_per_page: 25,
    offset: 25,
    items: [
        { ... },
        { ... },
        { ... },
        ...
    ]
}

失败(未找到数据)

{
    success: false,
    error: {
        code: 200,
        message: "Server is busy"
    }
}

我想使用带有GSON的Retrofit 2围绕此API构建包装并转换为POJO,但是我不确定如何处理API可能返回两个完全不同的模式这一事实。现在,我有以下课程:

public class PaginatedResponse<T> {
    private int item_count;
    private int items_per_page;
    private int offset;
    private List<T> items;

    public PaginatedResponse<T>(int item_count, int items_per_page, int offset, List<T> items) {
        this.item_count = item_count;
        this.items_per_page = items_per_page;
        this.offset = offset;
        this.items = items;
    }

    public List<T> getItems() {
        return this.items;
    }
}
public class Item {
    private int id;
    private String name;
    // ...
}

然后使用我的API接口:

public interface API {
    @GET("items")
    Call<PaginatedResponse<Item>> getItems();
}

然后最后我要说:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://localhost")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

API api = retrofit.create(API.class);

api.getItems().enqueue(new retrofit2.Callback<PaginatedResponse<Broadcast>>() {
    @Override
    public void onResponse(Call<PaginatedResponse<Broadcast>> call, Response<PaginatedResponse<Broadcast>> response) {
        Log.d("SUCCESS", response.body().getItems().toString());
    }

    @Override
    public void onFailure(Call<PaginatedResponse<Broadcast>> call, Throwable t) {
        Log.d("FAILURE", t.toString());
    }
}

只要没有错误抛出,这似乎是可行的。但是,当引发错误时,我在Logcat中得到以下内容,并且我的应用程序崩溃了:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference

由于失败JSON缺少items属性,因此将List<Item> items设置为null

1 个答案:

答案 0 :(得分:1)

  

这似乎是因为失败的JSON缺少items属性,它会将List items设置为null

是的,是的。您得到NullPointerException,因为您在一个空对象上调用了toString()。这是预期的行为。

解决方案

由于errorsuccess具有不同的架构,因此需要创建具有两个值的模型。下面给出了一个最小的示例,

ResponseModel.java


class ResponseModel {

    // ERROR
    private final Boolean success;
    private final Error error;

    // SUCCESS
    private final int item_count;
    // more success values... 

    ResponseModel(Boolean success, Error error, int item_count) {
        this.success = success;
        this.error = error;
        this.item_count = item_count;
    }

    public class Error {
        private final int code;
        private final String message;

        private Error(int code, String message) {
            this.code = code;
            this.message = message;
        }

        public int getCode() {
            return code;
        }

        public String getMessage() {
            return message;
        }

    }

    public Boolean getSuccess() {
        return success;
    }

    public Error getError() {
        return error;
    }

    public int getItem_count() {
        return item_count;
    }
}

并通过onResponse方法,您可以检查响应是否成功

ResponseModel responseModel = response.body();

if (responseModel.getError() == null) {
    // success
    doSomethingWithSuccess(responseModel.getItem_count())
} else {
    // error
    doSomethingWithError(responseModel.getError())
}