Android Gson 解析Json數據過程和如何自定義解析規則(下)

上兩篇文章主要講述尋找問題根源到解決思路,解決辦法比較複雜,這裏提供一種最簡單的解決辦法,不需要改動太多的東西:

比如一般後臺返回的數據格式如下:

正常數據

{"code":200,"data":{"id":"adsd","name":"Weipru"},"msg":"success","timeStamp":"20191015102953"}

不存在data的數據

{"code":1000,"data":"","msg":"請登錄!","timeStamp":"20191014094718"}

對應我們自己的Http響應實體


public class HttpMessage<T> {
    private int code;
    private T data;
    private String msg;
    private String timeStamp;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public String getTimeStamp() {
        return timeStamp;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public void setTimeStamp(String timeStamp) {
        this.timeStamp = timeStamp;
    }
    
}

正常訪問後臺流程

  • 後臺API
public interface GsonTestAPI {
    @GET("/user/list")
    Call<HttpMessage<List<UserAuthen>>> getUserList();

    @GET("/user/info")
    Call<HttpMessage<UserInfo>> getUserInfo();
}
  • 調用API,獲取數據
  messageCall.enqueue(new Callback<HttpMessage<UserInfo>>() {
            @Override
            public void onResponse(Call<HttpMessage<UserInfo>> call, Response<HttpMessage<UserInfo>> response) {
                Log.i(TAG, "onResponse: " + response.body().getCode());
            }

            @Override
            public void onFailure(Call<HttpMessage<UserInfo>> call, Throwable t) {
                Log.i(TAG, "onResponse: " + t.getMessage());
                t.printStackTrace();
            }
        });

同理,data類型爲泛型數組時:

  Call<HttpMessage<List<UserAuthen>>> messageCall = userServiceAPI.getUserList();
        messageCall.enqueue(new Callback<HttpMessage<List<UserAuthen>>>() {
            @Override
            public void onResponse(Call<HttpMessage<List<UserAuthen>>> call, Response<HttpMessage<List<UserAuthen>>> response) {
                Log.i(TAG, "onResponse: " + response.body().getCode());
            }

            @Override
            public void onFailure(Call<HttpMessage<List<UserAuthen>>> call, Throwable t) {
                Log.i(TAG, "onResponse: " + t.getMessage());
                t.printStackTrace();
            }
        });

如果返回正常數據,則可以正確解析並返回,否正直接拋出異常,怎麼解決呢?

同樣也需要自定義一個自己的轉換器,需要三個類:

  • GsonConverFactory
  • GsonResponseBodyConverter
     
  • GsonRequestBodyConverter

直接從源碼中複製出來 換成自己的名字即可,,現在只處理響應體轉換器GsonResponseBodyConverter,代碼如下:

  • 在GsonConverFactory中返回自己的轉換器,至展示關鍵部分

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        Log.w("TYPE", "類型是 " + type.getTypeName());//
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new WGsonResponseBodyConverter<>(gson, adapter);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type,
                                                          Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new WGsonRequestBodyConverter<>(gson, adapter);
    }
  • 在WGsonResponseBodyConverter中做狀態判斷:
 public T convert(ResponseBody value) throws IOException {
        try {
            //因爲value只能被讀取一次,所以這裏必須把讀取結果存起來,給下次使用
            String reponseString = value.string();
            HttpMessage httpMessage = gson.fromJson(reponseString, HttpMessage.class);
            if (httpMessage.getCode() != 200) {
                return (T) httpMessage;//直接返回,data字段不做類型轉換
            }

            MediaType contentType = value.contentType();
            Charset charset = contentType != null ? contentType.charset(UTF_8) : UTF_8;
            InputStream inputStream = new ByteArrayInputStream(reponseString.getBytes());
            Reader reader = new InputStreamReader(inputStream, charset);
            JsonReader jsonReader = gson.newJsonReader(reader);

            return adapter.read(jsonReader);
        } finally {
            value.close();
        }
    }

使用自定義的轉換器即可:

 userServiceAPI = new Retrofit.Builder()
                .client(builder.build())
                .baseUrl(this.host).addConverterFactory(WGsonConverFactory.create())//使用自己的轉換器
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .build()
                .create(GsonTestAPI.class);

簡單而完美地解決問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章