安卓使用retrofit統(tǒng)一處理服務(wù)器請求錯誤

正常情況下我們開發(fā)app服務(wù)器返回的json一般是這樣標(biāo)準(zhǔn)的形式辖源。

{
  "status": 1,
  "msg": "message",
  "data":{}
}

所以我們可以在客戶端定義這樣的格式來進(jìn)行統(tǒng)一處理肠阱。

public class Result<T> {
  public int status;
  public String msg;
  public T data;
}

最近遇到了這樣的問題落蝙,服務(wù)器返回的data有時候是對象,有時候又是數(shù)組算墨,還有可能是字符串绍坝,這樣使用第三方解析就比較麻煩了徘意。但是需要處理返回code不為0的情況,比如給用戶一些提示什么的轩褐。所以寫下來作為記錄椎咧,防止以后再遇到。遇到這種坑,要么和后臺協(xié)商返回統(tǒng)一格式的json字符串勤讽,如果后臺不改蟋座,我們只能自己解決了。

一脚牍、使用自定義ConvertAdapter

Retrofit可以使用自定義的Converter向臀,它的作用是可以將接受到的json轉(zhuǎn)換成實體返回給我們。

Retrofit retrofit = new Retrofit.Builder()
        .baseUrl(ApiService.API_BASE_URL)
        .client(okHttpClient)
        .addConverterFactory(GsonConverterFactory.create()) // 就是這里
        .addCallAdapterFactory(RxJavaCallAdapterFactory.createWithScheduler(Schedulers.io()))
        .build();

一般情況下我們都使用GsonConverterFactory诸狭,當(dāng)請求到j(luò)son后券膀,Retrofit就會調(diào)用GsonConverter將json轉(zhuǎn)成我們需要的實體。

GsonConverterFactory一共只有三個類驯遇,并且代碼量很少芹彬,如下:

public final class MyGsonConverterFactory extends Converter.Factory {
    /**
     * Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static MyGsonConverterFactory create() {
        return create(new Gson());
    }

    /**
     * Create an instance using {@code gson} for conversion. Encoding to JSON and
     * decoding from JSON (when no charset is specified by a header) will use UTF-8.
     */
    public static MyGsonConverterFactory create(Gson gson) {
        return new MyGsonConverterFactory(gson);
    }

    private final Gson gson;

    private MyGsonConverterFactory(Gson gson) {
        if (gson == null) throw new NullPointerException("gson == null");
        this.gson = gson;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        return new MyGsonResponseBodyConverter<>(gson, type);
    }

    @Override
    public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
        TypeAdapter<?> adapter = gson.getAdapter(TypeToken.get(type));
        return new MyGsonRequestBodyConverter<>(gson, adapter);
    }
}
final class MyGsonRequestBodyConverter<T> implements Converter<T, RequestBody> {
    private static final MediaType MEDIA_TYPE = MediaType.parse("application/json; charset=UTF-8");
    private static final Charset UTF_8 = Charset.forName("UTF-8");

    private final Gson gson;
    private final TypeAdapter<T> adapter;

    MyGsonRequestBodyConverter(Gson gson, TypeAdapter<T> adapter) {
        this.gson = gson;
        this.adapter = adapter;
    }

    @Override
    public RequestBody convert(T value) throws IOException {
        Buffer buffer = new Buffer();
        Writer writer = new OutputStreamWriter(buffer.outputStream(), UTF_8);
        JsonWriter jsonWriter = gson.newJsonWriter(writer);
        adapter.write(jsonWriter, value);
        jsonWriter.close();
        return RequestBody.create(MEDIA_TYPE, buffer.readByteString());
    }
}

主要操作在這個類進(jìn)行

public class MyGsonResponseBodyConverter<T> implements Converter<ResponseBody, T> {

    private final Gson gson;
    private final Type type;

    MyGsonResponseBodyConverter(Gson gson, Type type) {
        this.gson = gson;
        this.type = type;
        apiHandle = new ApiHandle();
    }


    @Override
    public T convert(ResponseBody value) throws IOException {
        String response = value.string();
        try {
            return gson.fromJson(response, type);
        } finally {
            value.close();
        }
    }

當(dāng)我們發(fā)出一個POST JSON請求(直接用Retrofit post一個實體給服務(wù)器,請求的時候會自動將我們的實體轉(zhuǎn)成Json)的時候叉庐,Retrofit就會調(diào)用GsonRequestBodyConverter的Convert方法將我們的實體轉(zhuǎn)換成json舒帮。而接受服務(wù)器返回的數(shù)據(jù)時,Retrofit會調(diào)用GsonResponseBodyConverter將Json數(shù)據(jù)轉(zhuǎn)換成我們需要的實體陡叠。
既然如此玩郊,我們可以在Converter解析json的時候就做服務(wù)器參數(shù)的統(tǒng)一處理
我是將GsonConverterFactory的三個類拷貝出來修改了一下:GsonConverterFactory和RequestBodyConverter幾乎沒有任何修改,我們需要更改類是GsonResponseBodyConverter枉阵,因為它才是將服務(wù)器的數(shù)據(jù)轉(zhuǎn)換成實體了译红,我們在轉(zhuǎn)換的過程中做統(tǒng)一處理。
這里需要說明的是因為后臺返回的data時刻會改變岭妖,所以我們需要解決這個問題临庇,我是這么處理的,首先自己定義一個類去存放code和message

public class BaseBean {
    private int code;
    private String msg;
    public int getCode() {
        return code;
    }

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

    public String getMsg() {
        return msg;
    }

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

這樣就能避免我們在解析data的時候出現(xiàn)解析錯誤昵慌,這里我的處理是在MyGsonResponseBodyConverter里面的convert方法攔截response

  public T convert(ResponseBody value) throws IOException {
        String response = value.string();
        try {
            BaseBean baseBean = gson.fromJson(response, BaseBean.class);//攔截code非0情況
            if (baseBean.getCode() != 0) {
                new Thread() {
                    @Override
                    public void run() {
                        Message msg = new Message();
                        msg.what = 1;
                        msg.obj = baseBean.getMsg();
                        handler.sendMessage(msg);
                    }
                }.start();
            }
            return gson.fromJson(response, type);
        } finally {
            value.close();
        }
    }

這里我們判斷code非0就是請求沒有達(dá)到我們定義的預(yù)期效果假夺,我這里是簡單處理給了個吐司,也可以定義接口回調(diào)處理斋攀,但是因為是子線程所以要用handler更新ui已卷。
一般情況下如果data格式固定可以在這里自定義異常處理,因為我是data不固定淳蔼,只能先取cade和message簡單處理侧蘸。最好還是和后臺小哥協(xié)商好最好了。最好不要遇到這種坑~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末鹉梨,一起剝皮案震驚了整個濱河市讳癌,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌存皂,老刑警劉巖晌坤,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逢艘,死亡現(xiàn)場離奇詭異,居然都是意外死亡骤菠,警方通過查閱死者的電腦和手機(jī)它改,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來商乎,“玉大人央拖,你說我怎么就攤上這事○钠荩” “怎么了鲜戒?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長崩瓤。 經(jīng)常有香客問我袍啡,道長踩官,這世上最難降的妖魔是什么却桶? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮蔗牡,結(jié)果婚禮上颖系,老公的妹妹穿的比我還像新娘。我一直安慰自己辩越,他們只是感情好嘁扼,可當(dāng)我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著黔攒,像睡著了一般趁啸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上督惰,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天不傅,我揣著相機(jī)與錄音,去河邊找鬼赏胚。 笑死访娶,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的觉阅。 我是一名探鬼主播崖疤,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼典勇!你這毒婦竟也來了劫哼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤割笙,失蹤者是張志新(化名)和其女友劉穎权烧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡豪嚎,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年搔驼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片侈询。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡舌涨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扔字,到底是詐尸還是另有隱情囊嘉,我是刑警寧澤,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布革为,位于F島的核電站扭粱,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏震檩。R本人自食惡果不足惜琢蛤,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抛虏。 院中可真熱鬧博其,春花似錦、人聲如沸迂猴。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽沸毁。三九已至峰髓,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間息尺,已是汗流浹背携兵。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留掷倔,地道東北人眉孩。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像勒葱,于是被迫代替她去往敵國和親浪汪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容