前言
开心原创哦
Retrofit 与RxJava结合,异常 处理都走了onError(Throwable t) 方法. 在该异常回调中,我们拿不到网络请求url等数据,只能拿到Throwable对象。
使用场景
异常统一处理,但异常回调中无法区分哪一个接口网络请求出现异常了。例如一个界面有多个接口,其中某个接口请求出现异常了,在异常统一处理里面无法区分。(使用场景):界面A有 下拉刷新和 上拉加载的接口, 同时还有点赞 、关注接口,当在上拉加载更多过程中,点赞接口触发,若某一接口请求失败,无法区分是上拉加载出现异常,还是点赞失败,这对于处理对应的UI是无法完成的。
解决方法一: 在不同接口里面传入对应的new Action
解决方法二: 在异常处理的回调中拿到对应接口的数据,如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 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 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'
如下图