背景
在之前的封装1-5中我们都是通过传统的GsonConverterFactory
自动解析,这样做确实很方便,用户能直接获取返回的对象,不用关心具体的转换,但是:这随之而来有很多的缺陷(虽然官网推荐这样使用);
比如:无法使用其他第三发转换框架;泛型无法中间传递,封装无法统一处理缓存结果;回调信息无法统一处理;服务器返回格式不严谨null解析异常..........
所以我们在享受它遍历的同时也被迫的要限制做很多的处理,限制我们的扩展!本章就介绍如何放弃GsonConverterFactory
,直接返回String
,扩展我们的封装!(封装的整体思想和之前的封装一样,所以不会有大的改动!)
无须担心,本篇封装单独作为一个项目和之前封装分开,便于大家选择!
效果
功能
完全具备和之前封装一样的功能,这里改用fastjson处理
1.Retrofit+Rxjava+okhttp基本使用方法 2.统一处理请求数据格式 3.统一的ProgressDialog和回调Subscriber处理 4.取消http请求 5.预处理http请求 6.返回数据的统一判断 7.失败后的retry处理 8.RxLifecycle管理生命周期,防止泄露 9.文件上传下载(支持多文件,断点续传) 10.Cache数据持久化和数据库(greenDao)两种缓存机制 11.一对多回调接口处理复制代码
对比
话说没有比较就没有进步,所以大家比较下前后封装的各自的优缺点,自行选择合适自己的方案!
使用
Gson
方案:
// 完美封装简化版 private void simpleDo() { SubjectPostApi postEntity = new SubjectPostApi(simpleOnNextListener,this); postEntity.setAll(true); HttpManager manager = HttpManager.getInstance(); manager.doHttpDeal(postEntity); } // 回调一一对应 HttpOnNextListener simpleOnNextListener = new HttpOnNextListener
>() { @Override public void onNext(List subjects) { tvMsg.setText("网络返回:\n" + subjects.toString()); } @Override public void onCacheNext(String cache) { /*缓存回调*/ Gson gson=new Gson(); java.lang.reflect.Type type = new TypeToken
>>() {}.getType(); BaseResultEntity resultEntity= gson.fromJson(cache, type); tvMsg.setText("缓存返回:\n"+resultEntity.getData().toString() ); } /*用户主动调用,默认是不需要覆写该方法*/ @Override public void onError(Throwable e) { super.onError(e); tvMsg.setText("失败:\n" + e.toString()); } /*用户主动调用,默认是不需要覆写该方法*/ @Override public void onCancel() { super.onCancel(); tvMsg.setText("取消請求"); } };复制代码
String
方案
// 完美封装简化版 private void simpleDo() { /*初始化数据*/ manager=new HttpManager(this,this); postEntity = new SubjectPostApi(); postEntity.setAll(true); manager.doHttpDeal(postEntity); } @Override public void onNext(String resulte, String mothead) { /*post返回处理*/ if(mothead.equals(postEntity.getMothed())){ ListsubjectResulte= JSONObject.parseArray(resulte,SubjectResulte.class); tvMsg.setText("post返回:\n"+subjectResulte.toString() ); } /*上传返回处理*/ if(mothead.equals(uplaodApi.getMothed())){ UploadResulte uploadResulte=JSONObject.parseObject(resulte,UploadResulte.class); tvMsg.setText("上传成功返回:\n"+uploadResulte.getHeadImgUrl()); Glide.with(MainActivity.this).load(uploadResulte.getHeadImgUrl()).skipMemoryCache(true).into(img); } } @Override public void onError(Throwable e) { tvMsg.setText("失败:\n" + e.toString()); }复制代码
Gson
封装方案中,我们采用了一一对应的返回原则,将所以的请求数据参数都放入到baseApi
中,返回放入对应的HttpOnNextListener
中
String
方案中我们则采用一对多原则,将回调和请求分开处理,公用一个回调,通过回调中的mothead
来区分不同的接口,所以上述可以看见后者里面其实还处理了上传的回调处理! 从封装的用法上可以看出:
优点:String
封装更加的灵活,可以指定Gson
转换的第三方工具,统一的结果返回处理代码更加的少(可以完美解决缓存无法统一回调的问题); 同样也有缺点:String
封装无法自动解析结果类型,需要手动处理(我反而觉得这也是它的优点,更加的灵活,个人看法)
实现
由于是基于之前的封装修改,所以前提是了解之前的封装以后才能完全了解一下的修改实现思路
1.替换GsonConverterFactory
由于GsonConverterFactory
会自动解析Gson
,替换成直接返回String
的ScalarsConverterFactory
导入相关包(为了区别-使用fastjson
可自由扩展)
compile 'com.squareup.retrofit2:converter-scalars:+' compile 'com.alibaba:fastjson:+'复制代码
替换
compile 'com.squareup.retrofit2:converter-gson:+' compile 'com.google.code.gson:gson:+'复制代码
2.修改retrofit构建
ScalarsConverterFactory
替换GsonConverterFactory
/*创建retrofit对象*/ Retrofit retrofit = new Retrofit.Builder() .client(builder.build()) .addConverterFactory(ScalarsConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(basePar.getBaseUrl()) .build(); HttpService httpService = retrofit.create(HttpService.class);复制代码
替换
/*创建retrofit对象*/ Retrofit retrofit = new Retrofit.Builder() .client(builder.build()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .baseUrl(basePar.getBaseUrl()) .build(); HttpService httpService = retrofit.create(HttpService.class);复制代码
3.修改缓存记录位置
由于之前是为了防止gson
重复解析,将缓存放入到自定义CookieInterceptor
中;既然现在不需要自动转换,直接返回String,所以直接将缓存数据处理放入到ProgressSubscriber
的onNext
中处理;
3.1:去掉CookieInterceptor
//手动创建一个OkHttpClient并设置超时时间缓存等设置 OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.addInterceptor(new CacheInterceptor()); builder.addNetworkInterceptor(new CacheInterceptor());复制代码
替换
//手动创建一个OkHttpClient并设置超时时间缓存等设置 OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.addNetworkInterceptor(new CacheInterceptor()); builder.addInterceptor(new CookieInterceptor(basePar.isCache()));复制代码
3.2:实现缓存处理
在onNext
中实现缓存处理
/** * 将onNext方法中的返回结果交给Activity或Fragment自己处理 * * @param t 创建Subscriber时的泛型类型 */ @Override public void onNext(T t) { /*缓存处理*/ if(api.isCache()){ CookieResulte resulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl()); long time=System.currentTimeMillis(); /*保存和更新本地数据*/ if(resulte==null){ resulte =new CookieResulte(api.getUrl(),t.toString(),time); CookieDbUtil.getInstance().saveCookie(resulte); }else{ resulte.setResulte(t.toString()); resulte.setTime(time); CookieDbUtil.getInstance().updateCookie(resulte); } } if (mSubscriberOnNextListener.get() != null) { mSubscriberOnNextListener.get().onNext((String) t,api.getMothed()); } }复制代码
4.修改回调接口信息
由于现在通过String
直接返回,所以可以将成功回调和缓存回调合并处理;另一方面没有了泛型的限制,在回调时可以通过接口请求参数实现一对多回调处理;
/** * 成功回调处理 * Created by WZG on 2016/7/16. */public interface HttpOnNextListener { /** * 成功后回调方法 * @param resulte * @param method */ void onNext(String resulte,String method); /** * 失败或者错误方法 * 主动调用,更加灵活 * @param e */ void onError(Throwable e);}复制代码
5.修改BaseApi
由于取消了泛型返回的机制,所以在Func1
判断时需要手动转换数据;这里示例fastjeson
用法转换
@Override public String call(T httpResult) { BaseResultEntity baseResulte= JSONObject.parseObject(httpResult.toString(),BaseResultEntity.class); if (baseResulte.getRet() == 0) { throw new HttpTimeException(baseResulte.getMsg()); } return baseResulte.getData(); }复制代码
替换
@Override public T call(BaseResultEntityhttpResult) { if (httpResult.getRet() == 0) { throw new HttpTimeException(httpResult.getMsg()); } return httpResult.getData(); }复制代码
6.修改结果基础类BaseResultEntity
将泛型数据改成String
数据类型
/** * 回调信息统一封装类 * Created by WZG on 2016/7/16. */public class BaseResultEntity { // 判断标示 private int ret; // 提示信息 private String msg; //显示数据(用户需要关心的数据) private String data; }复制代码
替换
/** * 回调信息统一封装类 * Created by WZG on 2016/7/16. */public class BaseResultEntity{ // 判断标示 private int ret; // 提示信息 private String msg; //显示数据(用户需要关心的数据) private T data; }复制代码
7.合并缓存和成功回到返回处理
由于取消泛型,缓存和成统一处理所以需要修改
/** * 订阅开始时调用 * 显示ProgressDialog */ @Override public void onStart() { showProgressDialog(); /*缓存并且有网*/ if(api.isCache()&& AppUtil.isNetworkAvailable(MyApplication.app)){ /*获取缓存数据*/ CookieResulte cookieResulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl()); if(cookieResulte!=null){ long time= (System.currentTimeMillis()-cookieResulte.getTime())/1000; if(time< api.getCookieNetWorkTime()){ if( mSubscriberOnNextListener.get()!=null){ mSubscriberOnNextListener.get().onNext(cookieResulte.getResulte(),api.getMothed()); } onCompleted(); unsubscribe(); } } } }复制代码
替换
/** * 订阅开始时调用 * 显示ProgressDialog */ @Override public void onStart() { showProgressDialog(); /*缓存并且有网*/ if(api.isCache()&& AppUtil.isNetworkAvailable(MyApplication.app)){ /*获取缓存数据*/ CookieResulte cookieResulte= CookieDbUtil.getInstance().queryCookieBy(api.getUrl()); if(cookieResulte!=null){ long time= (System.currentTimeMillis()-cookieResulte.getTime())/1000; if(time< api.getCookieNetWorkTime()){ if( mSubscriberOnNextListener.get()!=null){ mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte()); } onCompleted(); unsubscribe(); } } } }复制代码
8.修改一对多回调处理
没有了泛型,可以修改HttpManager
,采用动态创建,动态回调的方法解决多嵌套耦合的问题
8.1去掉默认构造传参
public BaseApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) { setListener(listener); setRxAppCompatActivity(rxAppCompatActivity); setShowProgress(true); setCache(true); }复制代码
8.2:添加HttpManager
动态传参
/** * http交互处理类 * Created by WZG on 2016/7/16. */public class HttpManager { /*弱引用對象*/ private SoftReferenceonNextListener; private SoftReference appCompatActivity; public HttpManager(HttpOnNextListener onNextListener, RxAppCompatActivity appCompatActivity) { this.onNextListener=new SoftReference(onNextListener); this.appCompatActivity=new SoftReference(appCompatActivity); } ******************* *******************}复制代码
8.3:通过method
动态判断接口返回
public class MainActivity extends RxAppCompatActivity implements HttpOnNextListener{ @Override public void onNext(String resulte, String method) { /*post返回处理*/ if(method.equals(postEntity.getMothed())){ ******* } /*上传返回处理*/ if(method.equals(uplaodApi.getMothed())){ ********* } } @Override public void onError(Throwable e) { tvMsg.setText("失败:\n" + e.toString()); } }复制代码
大功告成!
下载模块
由于下载模块是独立存在,所以基本没有修改,唯一修改的地方就是将HttpDownManager
中的GsonConverterFactory
替换成ScalarsConverterFactory
即可!
总结
通过自定义String
类型的返回处理方式,有效的解决了之前Gson
自动转换的问题
1.一对一返回问题(代码量多)
2.缓存回调无法和成功统一处理
3.无法指定
gson
转换第三方库4.回调监听的多嵌套(耦合度大)
5.解决服务器数据
null
异常
注意:这里只是给大家提供了一个不同的解决方案,Gson
自动解析返回的方案也是有它的优点,可以大大的减少开发的工作量,优缺点也很明显;孰好孰坏自行判断,自行选择适合自己的方案(个人偏向后者String
返回,比较灵活)