1. 程式人生 > >Retrofit網路異常回調中拿到網路請求url等資料

Retrofit網路異常回調中拿到網路請求url等資料

前言

開心原創哦

Retrofit 與RxJava結合,異常 處理都走了onError(Throwable t) 方法.  在該異常回調中,我們拿不到網路請求url等資料,只能拿到Throwable物件。

使用場景

異常統一處理,但異常回調中無法區分哪一個介面網路請求出現異常了。例如一個介面有多個介面,其中某個介面請求出現異常了,在異常統一處理裡面無法區分。(使用場景):介面A有  下拉重新整理和 上拉載入的介面, 同時還有點贊 、關注介面,當在上拉載入更多過程中,點贊介面觸發,若某一介面請求失敗,無法區分是上拉加載出現異常,還是點贊失敗,這對於處理對應的UI是無法完成的。

解決方法一: 在不同接口裡面傳入對應的new Action<Throwable>, 這 樣每個介面單獨處理 自己的異常回調

解決方法二: 在異常處理的回撥中拿到對應介面的資料,如url等,這樣就可以區分是哪個介面網路請求異常了。

方法一大家一般都知道如何使用,我就不作累述了。

在Rxjava 的onError回撥中拿到網路請求的URL等資料

在建立Retrofit物件時,會傳入CallAdapter.Factory 物件,該物件是專門處理回撥的。包括成功、失敗回撥。

如下: 

new Retrofit.Builder().addCallAdapterFactory(RxJavaCallAdapterFactory.create());

因為使用Rxjava與Retrofit結合,所以這裡添加回調是使用RxJavaCallAdapterFactory建立的。

由於每一個版本的Retrofit的原始碼都略有不一樣,但原理相同,大家可以根據我的思路去解決。我司的專案依賴的2.1.0版本

    compile 'com.squareup.retrofit2:retrofit:2.1.0'
    compile 'com.squareup.retrofit2:converter-gson:2.1.0'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

查看了RxJavaCallAdapterFactory的原始碼,Retrofit與Rxjava結合使用時,回撥處理都交給了這個庫來作處理,將Retrofit丟擲的異常給Rxjava的onError回撥,將請求成功給onNext和onComplete

'com.squareup.retrofit2:adapter-rxjava:2.1.0

通過debug可以發現所有回撥最後都走了RxJavaCallAdapterFactory 裡面的這個方法。

 @Override
    public void request(long n) {
      if (n < 0) throw new IllegalArgumentException("n < 0: " + n);
      if (n == 0) return; // Nothing to do when requesting 0.
      if (!compareAndSet(false, true)) return; // Request was already triggered.

      try {
        Response<T> response = call.execute();
        if (!subscriber.isUnsubscribed()) {
          subscriber.onNext(response);
        }
      } catch (Throwable t) {
        Exceptions.throwIfFatal(t);
        if (!subscriber.isUnsubscribed()) {
//          MyNetThrowable myNetThrowable = new MyNetThrowable(t, call);
          subscriber.onError(t);
        }
        return;
      }

      if (!subscriber.isUnsubscribed()) {
        subscriber.onCompleted();
      }
    }

為了在onError回撥中拿到網路url等資料,在這裡我們可以 自定義一個Throwable,然後將網路的Call物件放進去,這樣通過Call物件就可以 拿到請求url, host,headers,請求引數等資料了。

自主 義Throwable物件 MyNetThrowable,如下:

public class MyNetThrowable extends Throwable {

    public final Call call;

    public MyNetThrowable(Throwable e, Call call) {
        super(e);
        this.call = call;
    }

    public Call getCall() {
        return call;
    }
}

然後修改RxJavaCallAdapterFactory的原始碼 即可。請注意上面註釋的那一行程式碼,

if (!subscriber.isUnsubscribed()) {
          MyNetThrowable myNetThrowable = new MyNetThrowable(t, call);
          subscriber.onError(myNetThrowable);
        }

這樣既可以拿到之前的Throwable物件,也可以拿到請求Call物件

使用:

在onError回撥方法中,mError是給Rxjava的onError回撥使用的,所有網路請求異常都會走這裡。

  protected final Action1<Throwable> mError = t -> {
        if (t instanceof MyNetThrowable) {
            MyNetThrowable t1 = (MyNetThrowable) t;
            Call call = t1.call;
            Request request = call.request();
            Headers headers = request.headers();
            HttpUrl url = request.url();
            URL url1 = url.url();

        }
}

這樣就可以知道哪一個介面網路請求出現異常了。

延伸

如何修改RxJavaCallAdapterFactory原始碼,如何自定義CallAdapterFactory、

檢視其原始碼可以發現RxJavaCallAdapterFactory是 不允許你對其自定義的,需要修改其原始碼打成jar包重新依賴。

備註: 2.1.0版本的是這個情況,現最新版本已經更新了,RxJavaCallAdapterFactory 的原始碼也更改頗多,但原理沒變,大家可以關注一下最新版本。

先從retrofit 的github網址上下載對應版本號的原始碼,然後做成android lib ,修改完成後打成aar包,將aar包中jar包複製出來放入專案的lib資料夾即可(該lib除了程式碼沒有其它資源,直接複製其jar包即可了,依賴也方便),不再使用如下方式依賴了。

compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

如下圖