实Retrofit2.0结合RxAndroid现网络请求网上有很多文章,这里不再详细介绍
Retrofit基本是一个业务请求,对应一个接口方法,因为其返回值不支持泛型,只能是具体的类。好处是结构清楚,缺点是业务请求就耦合的网络接口,如果以后想分离网络就很麻烦。而且开发人员还要同时定义每个业务的请求接口,和具体的请求方式,对于大型APP,工作量很大,而且容易出错。
本文主要介绍如何对Retrofit2.0+RxAndroid封装成网络层,对业务使用隔离,使用者不需要知道网络框架使用的是哪种技术,只需要使用通用的接口,即可实现不同业务请求的调用。
下面这种泛型返回类型,Retrofit在运行是会报错,啃爹啊。
@GET(ACTION_URL)
<T extends BaseResult> Observable<T> requestNetwokData(@Query("a") String type, @QueryMap Map<String, String> options);
下面是变相的实现方式,基本技术不变,只是在服务器返回数据时做了一个简单的处理。
1. 返回的数据使用OKHttp原始的类型ResponseBody
2. 数据返回后,通过RxAndroid的map方法,强制根据调用者要求的类型进行转换
@GET(ACTION_URL)
Observable<ResponseBody> requestNetwokData(@Query("a") String type, @QueryMap Map<String, String> options);
public void startRequest(ServiceMap serviceMap, Map<String, String> paramMap) {
NetworkResult networkResult = new NetworkResult();
networkResult.mServiceMap = serviceMap;
Observable<ResponseBody> observable = mHttpApi.requestNetwokData(serviceMap.getmServiceType(), paramMap);
subscribeOn(networkResult, observable);
}
private void subscribeOn(final NetworkResult networkResult, final Observable<ResponseBody> observable) {
Subscription subscription = observable.subscribeOn(Schedulers.io())
// subscribe()调用后而且在事件发送前执行
// 默认情况下,doOnSubscribe()执行在subscribe()发生的线程
// 如果在doOnSubscribe()之后有subscribeOn()的话,它将执行在离它最近的subscribeOn()所指定的线程
.doOnSubscribe(new Action0() {
@Override
public void call() {
postNetSubscribe(SubscribeNetwork.TAG_NET_ONSTART, networkResult);
}
}).subscribeOn(AndroidSchedulers.mainThread())
.map(new Func1<ResponseBody, BaseResult>() {
@Override
public BaseResult call(ResponseBody resBody) {
NLog.e("retrofit", "map thread " + Thread.currentThread());
try {
return JSON.parseObject(resBody.bytes(), networkResult.mServiceMap.getmClazz());
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<BaseResult>() {
@Override
public void onCompleted() {
postNetSubscribe(SubscribeNetwork.TAG_NET_ONCOMPLETED, networkResult);
}
@Override
public void onError(Throwable e) {
postNetSubscribe(SubscribeNetwork.TAG_NET_ONERROR, networkResult);
}
@Override
public void onNext(BaseResult baseResult) {
NLog.e("retrofit", "onNext thread " + Thread.currentThread());
networkResult.mResponseResult = baseResult;
postNetSubscribe(SubscribeNetwork.TAG_NET_ONRESULT, networkResult);
}
});
// add方法内做了线程同步功能
mCompositeSubscription.add(subscription);
}
上面就是本人的变相处理方式,哪位大神有好的方法,欢迎指导。
RxBus post方法遇到的坑
1. 使用post方法通知订阅者,网络数据返回
/**
* 给订阅者发网络处理消息
* @param tag
* @param networkResult
*/
private void postNetSubscribe(String tag, @NonNull NetworkResult networkResult) {
if (networkResult.mResponseResult == null) {
// 保证mResponseResult永远都不为null
networkResult.mResponseResult = new BaseResult();
}
RxBus.get().post(tag, networkResult);
}
2. 通用的订阅者,接收网络数据返回,再分发给不同界面
public class SubscribeNetwork {
private INetworkListener networkListener;
public SubscribeNetwork(INetworkListener listener) {
this.networkListener = listener;
}
public void register() {
// 网络请求处理结果监听
RxBus.get().register(this);
}
public void unregister() {
// 解除网络处理结果监听
RxBus.get().unregister(this);
}
@Subscribe(tags = {@Tag(TAG_NET_ONRESULT)})
public void subscribeNetResult(NetworkResult networkResult) {
if (networkListener != null) {
networkListener.onNetResult(networkResult);
}
}
}
3. SubscribeNetwork的注册,是在Fragment创建时,初始化的。
问题:
在使用ViewPager + Fragment时,默认会创建2个Fragment,即会注册2个RxBus的订阅者。
不论第二个Fragment是否进行网络请求,再第一个网络请求返回时,都会调用subscribeNetResult方法,进而调用networkListener的回调。
所以导致Fragment的网络回调会多次调用。
解决:
只能使用接口方式,进行返回,不使用rxbus的post方式。
/** * 给订阅者发网络处理消息 * @param tag * @param networkResult */ private void postNetSubscribe(String tag, @NonNull NetworkResult networkResult) { if (networkResult.mResponseResult == null) { // 保证mResponseResult永远都不为null networkResult.mResponseResult = new BaseResult(); } // RxBus.get().post(tag, networkResult); if (mNetworkListener != null) { if (INetworkListener.TAG_NET_ONSTART.equals(tag)) { mNetworkListener.onNetStart(networkResult); } else if (INetworkListener.TAG_NET_ONRESULT.equals(tag)) { mNetworkListener.onNetResult(networkResult); } else if (INetworkListener.TAG_NET_ONCOMPLETED.equals(tag)) { mNetworkListener.onNetCompleted(networkResult); } else if (INetworkListener.TAG_NET_ONERROR.equals(tag)) { mNetworkListener.onNetError(networkResult); } } }