rxjava+retrofit2深度封装
Rxjava+Retrofit网络框架的封装使用如今是非常流行的,看过不少的使用案例,却发现在使用过程中代码量还是比较多的,或者就干脆使用最原始的方法,对于有强迫症的我很难忍受,多一行代码都会让我觉得多余,不愿意去做重复的事情,尽我所能去封装到最少的代码,这就是我。
RxJava:按我的理解就是异步处理机制,当然也可以同步,类似于handle和AsyncTask,好处就同一代码块实现子线程和UI线程的操作,整体风格整洁易读。如果还为对rxjava有所理解,请参考:http://gank.io/post/560e15be2dca930e00da1083;Rxjava不仅仅用于网络方面的请求,比如线程通信,android权限申请等,请参考:http://blog.csdn.net/lzyzsd/article/details/50120801;
Retrofit2:一款Square公司开发的现在非常流行的网络框架,其特点是非常简洁,性能好,处理快,目前发现的缺点就是上传大文件OOM,上传大文件建议使用张鸿洋基于okhttp封装的okgo;
废话不多说,进入正题。
第一步:引入Rxjava和Retrofit依赖
compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'io.reactivex:rxjava:1.0.14' compile 'io.reactivex:rxandroid:1.0.1' compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
第二步 获取Retrofit示例
/**
* 获取Retrofit示例
* @param apiUrl
* @return
*/
private Retrofit.Builder getBuilder(String apiUrl) {
Retrofit.Builder builder = new Retrofit.Builder();
builder.client(getOkClient());
builder.baseUrl(apiUrl);//设置远程地址
builder.addConverterFactory(new NullOnEmptyConverterFactory());
builder.addConverterFactory(GsonConverterFactory.create(getGson()));
builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
return builder;
}
第三步 获取请求服务
/**
* 一般请求服务
* @param a
* @param <T>
* @return
*/
public T createRequest(Class a) {
if (httpTask == null) {
synchronized (HttpUtils.class) {
if (httpTask == null) {
httpTask = getBuilder(Api.HOST_URL).build().create(a);
}
}
}
return (T) httpTask;
}
/**
* 自定义请求服务
* @param a
* @param <T>
* @return
*/
public T createRequest(Class a,String baseUrl) {
if(!customHttpMaps.containsKey(baseUrl)){
customHttpMaps.put(baseUrl,getBuilder(baseUrl).build().create(a));
}
return (T) customHttpMaps.get(baseUrl);
}
最后,整个代码创建在一个类里面,并使用带锁的单例模式获取示例,避免频繁的创建示例,造成没有必要的开销,整个代码如下:
/**
*
* 刘宇飞 创建 on 2017/5/15.
* 描述:
*/
public class HttpUtils {
private Gson gson;
private static volatile HttpUtils instance;
private volatile Object httpTask;
private static HashMap customHttpMaps = new HashMap<>();
/**
* 单例
* @return
*/
public static HttpUtils getInstance() {
if (instance == null) {
synchronized (HttpUtils.class) {
if (instance == null) {
instance = new HttpUtils();
}
}
}
return instance;
}
/**
* 获取Retrofit示例
* @param apiUrl
* @return
*/
private Retrofit.Builder getBuilder(String apiUrl) {
Retrofit.Builder builder = new Retrofit.Builder();
builder.client(getOkClient());
builder.baseUrl(apiUrl);//设置远程地址
builder.addConverterFactory(new NullOnEmptyConverterFactory());
builder.addConverterFactory(GsonConverterFactory.create(getGson()));
builder.addCallAdapterFactory(RxJavaCallAdapterFactory.create());
return builder;
}
private OkHttpClient getOkClient() {
//使用OkHttp拦截器可以指定需要的header给每一个Http请求
OkHttpClient client = new OkHttpClient().newBuilder()
.readTimeout(20, TimeUnit.SECONDS)
.connectTimeout(20, TimeUnit.SECONDS)
.retryOnConnectionFailure(true)
.writeTimeout(20, TimeUnit.SECONDS)
.addInterceptor(new LoggingInterceptor())//日志
// .addInterceptor(new NotEdcodeLoggingInterceptor())//不加密
// .addNetworkInterceptor(new RequestHeaderInterceptor())//请求头
.build();
return client;
}
private Gson getGson() {
if (gson == null) {
GsonBuilder builder = new GsonBuilder();
builder.setLenient();
builder.setFieldNamingStrategy(new AnnotateNaming());
builder.serializeNulls();
gson = builder.create();
}
return gson;
}
private static class AnnotateNaming implements FieldNamingStrategy {
@Override
public String translateName(Field field) {
ParamNames a = field.getAnnotation(ParamNames.class);
return a != null ? a.value() : FieldNamingPolicy.IDENTITY.translateName(field);
}
}
/**
* 一般请求服务
* @param a
* @param <T>
* @return
*/
public T createRequest(Class a) {
if (httpTask == null) {
synchronized (HttpUtils.class) {
if (httpTask == null) {
httpTask = getBuilder(Api.HOST_URL).build().create(a);
}
}
}
return (T) httpTask;
}
/**
* 自定义请求服务
* @param a
* @param <T>
* @return
*/
public T createRequest(Class a,String baseUrl) {
if(!customHttpMaps.containsKey(baseUrl)){
customHttpMaps.put(baseUrl,getBuilder(baseUrl).build().create(a));
}
return (T) customHttpMaps.get(baseUrl);
}
/**
* 清空重建 防止切换账号 使用共同的请求
*/
public void clearHttp(){
instance=null;
httpTask=null;
customHttpMaps.clear();
gson=null;
}
}
第四步 与RXjava的结合 关键所在
我采用构建者设计模式,更加灵活的定制需要,首先创建一个抽象工厂,有以下方法:
HttpBuilder setRequsetId(int requsetId);//请求id
HttpBuilder setContext(Context context);//上下文
HttpBuilder setObservable(Observable observable);//观察者
Subscription create(); //创建示例
HttpBuilder setCallBack(HttpTaskListener listener); //网络监听
最后一步 请求的封装
需要注意的是,请求默认加载进度框,并要对请求进行管理,否则容易出现空指针异常。
private Subscription request() {
//避免没有必要的请求
if(CheckNetwork.isNetworkConnected(MyApplication.getContext())){
CommonUtils.showToast(MyApplication.getContext(),"无网络连接,请检查网络");
return null;
}
if(context!=null){//如果context不为空则显示进度框
CommonUtils.getInstance().showInfoProgressDialog(context);
}
Subscription subscribe = observable
.subscribeOn(Schedulers.newThread())//请求网络在子线程中
.observeOn(AndroidSchedulers.mainThread())//回调在主线程中
.subscribe(new Subscriber>() {
@Override
public void onCompleted() {
CommonUtils.getInstance().hideInfoProgressDialog();
}
@Override
public void onError(Throwable e) {
CommonUtils.getInstance().hideInfoProgressDialog();
if(listener!=null){
listener.onException(requstId);
}
}
@Override
public void onNext(BaseRespose baseResponseVo) {
CommonUtils.getInstance().hideInfoProgressDialog();
if(listener!=null){
listener.onSuccess(requstId,baseResponseVo.data);
}
}
});
//activity 或者fragment销毁时 必须销毁所有的请求 不然容易导致空指针
CommonUtils.getInstance().addSubscription(subscribe);
return subscribe;
}
这就封装完成了,最后看看如何使用吧,一行代码搞定。
HttpPresenter.getInstance()
.setRequsetId(10) //请求id 非必须
.setContext(mContext) //上下文 非必须 没有不显示进度框
.setObservable(httpTask.requestLogin(map)) //必须
.setCallBack(this) //回调 非必须
.create();
更多封装细节,请下载我的github项目:https://github.com/tzz2015/commonLib.git 如有建议,请联系本人,感激不尽。
ost.com{Ȝۡ>