RxJava2 + Retrofit2 完全指南 之 對返回Response的統一處理

weixin_34148340發表於2019-02-14

前言

本章在上篇統一狀態碼/Exception處理的基礎上進行擴充,請現有一個必要的概念。

在介面對接中,我們最理想的狀態就是後端只返回一種資料結構,而且是規範的資料結構,但事實上大多數情況下都不會按照我們的理想狀態下返回的,比方說有資料的情況下,返回的是一種結構,無資料包錯又是另外一種資料結構,這就不可避免的需要我們對每個請求進行判斷,雖然可以通過和()(P)諧(Y)交(J)談(Y)來讓後端返回相同資料結構。但也存在另外一種情況:一個APP接入不同公司的API,這種情況就是無法避免的了。
對此,我們通過Retrofit可以在進行轉換之前進行統一的資料結構判斷和轉換,只將資料data返回,只關注資料結果就行。

實現

分析

為了模擬相關資料結構,我在原本的基礎上增加了兩種種不同的資料,然後通過隨機數獲取到其中的一個資料當做返回結果來操作,兩種資料格式如下:

  • 資料格式 1
{
    "code": 200,
    "data": {
        "id": "1",
        "name": "資料格式 1",
        "stargazers_count": 1
    }
}
  • 資料格式 2
{
    "status": 200,
    "msg": "請求成功",
    "userInfo": {
        "id": "2",
        "name": "資料格式 2",
        "stargazers_count": 2
    }
}

分析兩種資料,datauserInfo中的欄位幾乎一致,當然現實基本上不會這樣的,這只是為了模擬一下這種情況,然後又是使用同一個實體類才這樣做。

編碼

先將上一個例子的三個類copy出來並重新命名。

1760510-6a99de9538f0ce52.png
CustConvert

對GsonResponseBodyConverter的convert方法進行修改,其實統一Resonse並沒有什麼難度,只是先一步將Resonse返回的資料使用原生的JSONObject先解析一遍,多加判斷,多加try而已,具體程式碼如下:

final class GsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {
    private final TypeAdapter<T> adapter;

    /**
     * 模擬的假資料
     */
    private final List<String> mockResult;

    private final Random random;

    GsonResponseBodyConverter(TypeAdapter<T> adapter) {
        this.random = new Random();
        this.adapter = adapter;
        mockResult = new ArrayList<>();
        mockResult.add("{\"code\":200,\"message\":\"成功,但是沒有資料\",\"data\":[]}");
        mockResult.add("{\"code\":-1,\"message\":\"這裡是介面返回的:錯誤的資訊,丟擲錯誤資訊提示!\",\"data\":[]}");
        mockResult.add("{\"code\":401,\"message\":\"這裡是介面返回的:許可權不足,請重新登入!\",\"data\":[]}");
        mockResult.add("{\"code\": 200,\"data\": {\"id\": \"1\",\"name\": \"資料格式 1\",\"stargazers_count\": 1}}");
        mockResult.add("{\n\"status\": 200,\"msg\": \"請求成功\",\"userInfo\": {\"id\": \"2\",\"name\": \"資料格式 2\",\"stargazers_count\": 2}}");
    }

    @Override
    public T convert(ResponseBody value) throws IOException {
        // 這裡就是對返回結果進行處理
        // 其實我根本就沒使用真正返回的結果,都是用的自定義的結果
        String jsonString = value.string();
        try {
            // 這裡為了模擬不同的網路請求,所以採用了本地字串的格式然後進行隨機選擇判斷結果。
            int resultIndex = random.nextInt(mockResult.size());

            // 這裡模擬不同的資料結構
            jsonString = mockResult.get(resultIndex);

            Log.e("TAG", "這裡進行了返回結果的判斷");


            JSONObject jsonObject = new JSONObject(jsonString);

            try {
                // 如果這裡能取出資料,而且沒有問題,那就代表這是 code data msg 資料格式的
                int code = jsonObject.getInt("code");
                if (code != 200) {
                    throw new NetErrorException(jsonObject.getString("message"), code);
                }
                try {
                    return adapter.fromJson(jsonObject.getString("data"));
                } catch (Exception e) {
                    throw new NetErrorException("資料解析異常", NetErrorException.PARSE_ERROR);
                }
            } catch (JSONException ignored) {

            }

            try {
                // 如果這裡能取出資料,而且沒有問題,那就代表這是 code data msg 資料格式的
                int status = jsonObject.getInt("status");
                if (status != 200) {
                    throw new NetErrorException(jsonObject.getString("msg"), status);
                }
                return adapter.fromJson(jsonObject.getString("userInfo"));
            } catch (JSONException e) {
                throw new NetErrorException("資料解析異常", NetErrorException.PARSE_ERROR);
            }


        } catch (JSONException e) {
            e.printStackTrace();
            throw new NetErrorException("資料解析異常", NetErrorException.PARSE_ERROR);
        } finally {
            value.close();
        }
    }
}

演示

1760510-0cc7aceda491fd8e.gif
MultipleResponse

結束

原始碼

廣告

如果對你有幫助,請給我一個star,感激不盡。
如果有什麼錯誤,請儘量提出來,我會及時修改。

相關文章