RxJava + Retrofit + OKHttp + RxLifecycle进一步封装网络
来源:互联网 发布:unity3d树叶是方形的 编辑:程序博客网 时间:2024/06/09 15:57
一、说明
RxJava和Retrofit的基本用法这里不再阐述,网络上有很多教程,这里只写进一步封装的过程,回顾一下我学习网络封装的知识。
二、封装过程
1、先把接口的数据格式理清楚,一般返回的Json格式都是这样:
{ "code":200 "msg":"成功" "results":{[data] }}
results里面的才是我们真正需要的实例,但是每个实例都不一样,因此要针对不同的数据来封装。
因此,先创建一个公共接口实例类HttpResult类,我们真正需要的实例先不初始化,用T来代替(例如MovieBean、GoodsBean这样的),我这里数据结构不一样,因此可能和你的不一样:
public class HttpResult<T> { private int ret; private String msg; private String token; private T result; public String getToken() { return token; } public void setToken(String token) { this.token = token; } public int getRet() { return ret; } public void setRet(int ret) { this.ret = ret; } public String getMsg() { return msg; } public void setMsg(String msg) { this.msg = msg; } public T getResult() { return result; } public void setResult(T result) { this.result = result; }}
2、首先创建一个Retrofit需要的interface,用来获取数据接口
例如:这里有一个仿拉手团购的公开接口,只有两个数据,这样的:
获取团购信息:http://7xij5m.com1.z0.glb.clouddn.com/spRecommend.txt
获取电影信息:http://7xij5m.com1.z0.glb.clouddn.com/filmHot_refresh.txt
因此我的APIService是这样写的:
public interface APIService { String base_url = "http://7xij5m.com1.z0.glb.clouddn.com/"; @GET("filmHot_refresh.txt") Observable<HttpResult<List<MovieBean>>> getMovie(); @GET("spRecommend.txt") Observable<HttpResult<GoodsBean>> getGoods();}
3、接口弄好了之后,接下来要初始化我们的Retrofit和OKHttp了,用一个HttpRetrofit来封装:
public class HttpRetrofit { private static final int DEFAULT_TIMEOUT = 10; private final APIService apiService; HttpRetrofit(){ OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); builder.readTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS); builder.writeTimeout(DEFAULT_TIMEOUT,TimeUnit.SECONDS); builder.retryOnConnectionFailure(true); Cache cache = new Cache(App.getAppContext().getCacheDir(),10 * 1024 * 1024); builder.cache(cache); builder.addInterceptor(new CacheInterceptor()); builder.addNetworkInterceptor(new CacheInterceptor()); apiService = new Retrofit.Builder() .client(builder.build()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .baseUrl(APIService.base_url) .build().create(APIService.class); } APIService getApiService(){ return apiService; }}
如果你会Retrofit的基本使用,上面的代码应该能看懂,CacheInterceptor我就不贴代码了,就是针对网络状况不同是否用缓存的一个判断。
3、将APIService单例化,用一个HttpFactory类来给外界调用:
public class HttpFactory { private static APIService apiService; private HttpFactory(){ } public static APIService getApiService(){ if(apiService == null){ synchronized (HttpFactory.class){ if(apiService == null){ apiService = new HttpRetrofit().getApiService(); } } } return apiService; }}
4、现在,我们已经进行了一个基本的封装,但是每次我们调用的时候都要重复写指定线程的代码,这样很麻烦,能不能一次性把它们封装好,以后调用的时候不用再写这一句代码了呢?答案是当然可以,RxJava为我们提供了一个Transformer类,它的作用是用来将一个Observable转换成另一个Observable,调用的时候使用compose操作符就行,它类似于flapmap操作符,但是效率更高(原因好像是它复用了Observable,这个具体我也不太清楚)。我们写一个HttpResultTransformer类:
public class HttpTransformer<R extends HttpResult<T>, T> implements Observable.Transformer<R,T>{ private ActivityLifecycleProvider provider; public HttpTransformer(ActivityLifecycleProvider provider){ this.provider = provider; } @Override public Observable<T> call(Observable<R> rObservable) { return rObservable.flatMap(new Func1<R, Observable<T>>() { @Override public Observable<T> call(R r) { if(r.getRet() != 0){ return createData(r.getResult()); }else { return Observable.error(new ApiException("网络出错")); } } }).subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .subscribeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread()) .compose(provider.<T>bindUntilEvent(ActivityEvent.PAUSE)); } private Observable<T> createData(final T data){ return Observable.create(new Observable.OnSubscribe<T>() { @Override public void call(Subscriber<? super T> subscriber) { try { subscriber.onNext(data); subscriber.onCompleted(); }catch (Exception e){ subscriber.onError(e); } } }); }}
这段代码有点复杂,我来说明一下,首先对我们获取的HttpResult进行一个判断返回码,如果返回码不正确,直接交给Observable去调用Error方法(其中APIException是我自己创建的一个异常类),就不再继续转换和发送请求了;如果返回码正确,那么我们要把HttpResult转换成我们真正需要的result,然后同时指定线程和RxLifecycle的接触绑定的方法,这样,就省略了很多代码。
在没有封装之前,我们写的代码是这样:
private void getGoods(){ HttpFactory.getApiService() .getGoods() .subscribeOn(Schedulers.io()) .unsubscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .compose(this.<HttpResult<GoodsBean>>bindUntilEvent(ActivityEvent.DESTROY)) .subscribe(new Subscriber<HttpResult<GoodsBean>>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(HttpResult<GoodsBean> httpResult) { GoodsBean bean = httpResult.getResult(); } }); }
封装之后,代码是这样的:
private void getGoods2(){ HttpFactory.getApiService() .getGoods() .compose(new HttpTransformer<HttpResult<GoodsBean>,GoodsBean>(this)) .subscribe(new Subscriber<GoodsBean>() { @Override public void onCompleted() { } @Override public void onError(Throwable e) { } @Override public void onNext(GoodsBean goodsBean) { } }); }
是不是清爽了很多?APIException的代码,我这里还没有写错误码处理:
public class ApiException extends IllegalAccessException { public ApiException(String s) { super(s); } public ApiException(int resultCode){ this(getApiExceptionMessage(resultCode)); } private static String getApiExceptionMessage(int code){ switch (code){ default: } return null; }}
5、最后,在我们访问网络的时候需要弹一个提示框,在访问结束后让提示框消失。
有一个问题要注意,我们如果在Subscriber的onStart里面弹框的话可能会有线程问题,但是RxJava已经为我们提供了解决办法,subscribeOn方法只有在第一次生效,而第二次subscriberOn时候可以让onStart方法在主线程执行(这里有疑问,应该是让doOnSubscriber在主线程执行,但是我在实际中发现onStart也在主线程执行了)。
因此,我们可以在Subscriber的onStart中弹框,在onComplete方法中取消弹框。这里,首先用一个ProgressDialogHander来封装我们的ProgressDialog,
ProgressDialogHander继承Handler,在需要的时候弹框,不需要的时候不弹框(这里有一个 ProgressDialogCannelListener用来做用户主动取消弹框后的操作(一般是取消订阅):
public class ProgressDialogHandler extends Handler { public static final int SHOW_PROGRESSDIALOG = 1; public static final int DISMISS_PROGRESSDIALOG = 2; interface OnProgressDialogCannelListener{ void onCannelProgress(); } private ProgressDialog mDialog; private Context mContext; private OnProgressDialogCannelListener mListener; private boolean canCannel; public ProgressDialogHandler(Context context,OnProgressDialogCannelListener listener,boolean canCannel){ this.mContext = context; this.mListener = listener; this.canCannel = canCannel; } private void initProgressDialog(){ if(mDialog == null){ mDialog = new ProgressDialog(mContext); mDialog.setCanceledOnTouchOutside(false); mDialog.setMessage("加载中 ..."); mDialog.setCancelable(canCannel); if(canCannel){ mDialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @Override public void onCancel(DialogInterface dialog) { mListener.onCannelProgress(); } }); } } if(!mDialog.isShowing()){ mDialog.show(); } } private void dissmissDialog(){ if(mDialog != null){ mDialog.dismiss(); mDialog = null; } } @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what){ case SHOW_PROGRESSDIALOG: initProgressDialog(); break; case DISMISS_PROGRESSDIALOG: dissmissDialog(); break; } }}
再写一个类ProgressSubscriber继承Subscriber,用来给用户回调请求成功或者失败的方法:
public abstract class ProgressSubscriber<T> extends Subscriber<T> implements ProgressDialogHandler.OnProgressDialogCannelListener { ProgressDialogHandler mHandler; public ProgressSubscriber(Context context){ mHandler = new ProgressDialogHandler(context,this,true); } @Override public void onStart() { super.onStart(); showDialog(); } @Override public void onCompleted() { dismissDialog(); } @Override public void onError(Throwable e) { if(false){//TODO 网络不可用 onFailed("网络不可用!"); } else if(e instanceof ApiException){ onFailed(e.getMessage()); } else { onFailed("请求失败,请稍后再试"); } } @Override public void onNext(T t) { onSuccess(t); } private void showDialog(){ if(mHandler != null){ mHandler.sendEmptyMessage(ProgressDialogHandler.SHOW_PROGRESSDIALOG); } } private void dismissDialog(){ if(mHandler != null){ mHandler.sendEmptyMessage(ProgressDialogHandler.DISMISS_PROGRESSDIALOG); mHandler = null; } } protected abstract void onSuccess(T t); protected abstract void onFailed(String message); @Override public void onCannelProgress() { if(!this.isUnsubscribed()){ this.unsubscribe(); } }}
至此,这次封装就结束了,我们去请求GoodBeans的操作就是这样了:
private void getGoods2(){ HttpFactory.getApiService() .getGoods() .compose(new HttpTransformer<HttpResult<GoodsBean>,GoodsBean>(this)) .subscribe(new ProgressSubscriber<GoodsBean>(this) { @Override protected void onSuccess(GoodsBean goodsBean) { } @Override protected void onFailed(String message) { } }); }
三、参考博客:
扔物线大神的RxJava经典教程
本文大部分学习的封装方法
- RxJava + Retrofit + OKHttp + RxLifecycle进一步封装网络
- 封装Retrofit + okhttp + rxjava网络请求框架
- 封装RxJava+Retrofit+OkHttp
- RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- 如何封装自己的网络框架(RxJava+okHttp+Retrofit)
- RxJava+Retrofit+OkHttp深入浅出-终极封装二(网络请求)
- retrofit+RxJava+okhttp简便封装实现网络请求(详解)
- Retrofit和RxJava加OkHttp网络请求进行二次封装
- Mvp+Retrofit+Rxjava+RxLifecycle的封装和使用
- Retrofit+OKhttp+RxJava框架的封装
- RxJava+okhttp+Retrofit+Mvp 的封装
- Rxjava+ReTrofit+okHttp深入浅出-终极封装
- RxJava+Retrofit+OkHttp 深入浅出-终极封装一
- 终极封装 Rxjava+Retrofit+okhttp+mvp实现
- 如何封装自己的网络框架 -进阶封装 (RxJava+okHttp+Retrofit)
- Rxjava和Retrofit网络封装
- ubuntu pppoe自动上网设置 及导致的路由器联网问题
- 一个简单的SpringMVC需要哪些jar包[Spring4]
- 31、互斥锁与进程间通信
- 腾讯大牛教你web前后端漏洞分析与防御-点击劫持,传输安全
- k-近邻算法
- RxJava + Retrofit + OKHttp + RxLifecycle进一步封装网络
- (HYSBZ
- Java实现简单二维码制作
- YAML
- 【leetcode】第55题 Jump Game 题目+解析+代码
- ICMP&&IP&&ARP
- spring + spring mvc + mybatis 整合框架
- c#基础:非泛型集合系列
- Android 基础 -- 生命周期和启动模式实践总结