美文网首页
<转>RxJava+Retrofit+OkHttp深入浅出-终极

<转>RxJava+Retrofit+OkHttp深入浅出-终极

作者: Vurtex | 来源:发表于2017-08-30 23:26 被阅读0次

    背景

    在之前的封装1-5Rxjava+ReTrofit+okHttp深入浅出-终极封装中我们都是通过传统的GsonConverterFactory自动解析,这样做确实很方便,用户能直接获取返回的对象,不用关心具体的转换,但是:这随之而来有很多的缺陷(虽然官网推荐这样使用);

    比如:无法使用其他第三发转换框架;泛型无法中间传递,封装无法统一处理缓存结果;回调信息无法统一处理;服务器返回格式不严谨null解析异常……….
    所以我们在享受它遍历的同时也被迫的要限制做很多的处理,限制我们的扩展!

    本章就介绍如何放弃GsonConverterFactory,直接返回String,扩展我们的封装!(封装的整体思想和之前的封装一样,所以不会有大的改动!)

    无须担心,本篇封装单独作为一个项目和之前封装分开,便于大家选择!


    效果

    1477899421_7354.gif

    功能

    完全具备和之前封装一样的功能,这里改用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<List<SubjectResulte>>() {
            @Override
            public void onNext(List<SubjectResulte> subjects) {
                tvMsg.setText("网络返回:\n" + subjects.toString());
            }
    
            @Override
            public void onCacheNext(String cache) {
                /*缓存回调*/
                Gson gson=new Gson();
                java.lang.reflect.Type type = new TypeToken<BaseResultEntity<List<SubjectResulte>>>() {}.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())){
                List<SubjectResulte>  subjectResulte= 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封装无法自动解析结果类型,需要手动处理(我反而觉得这也是它的优点,更加的灵活,个人看法)


    实现

    由于是基于之前的封装修改,所以前提是了解之前的封装以后才能完全了解一下的修改实现思路RxJava+Retrofit+OkHttp深入浅出-终极封装专栏

    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中处理;

    修改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()));
    
    修改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(BaseResultEntity<T> httpResult) {
            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<T> {
        //  判断标示
        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,采用动态创建,动态回调的方法解决多嵌套耦合的问题

    修改1:去掉默认构造传参
    public BaseApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
            setListener(listener);
            setRxAppCompatActivity(rxAppCompatActivity);
            setShowProgress(true);
            setCache(true);
        }
    
    修改2:添加HttpManager动态传参
    /**
     * http交互处理类
     * Created by WZG on 2016/7/16.
     */
    public class HttpManager {
        /*弱引用對象*/
        private SoftReference<HttpOnNextListener>  onNextListener;
        private SoftReference<RxAppCompatActivity> appCompatActivity;
    
        public HttpManager(HttpOnNextListener onNextListener, RxAppCompatActivity appCompatActivity) {
            this.onNextListener=new SoftReference(onNextListener);
            this.appCompatActivity=new SoftReference(appCompatActivity);
        }
        *******************
        *******************
    }
    
    修改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返回,比较灵活)

    源码

    源码传送门-String变种方案-Github
    源码传送门-Gson方案-Github

    终极封装专栏

    RxJava+Retrofit+OkHttp深入浅出-终极封装专栏

    相关文章

      网友评论

          本文标题:<转>RxJava+Retrofit+OkHttp深入浅出-终极

          本文链接:https://www.haomeiwen.com/subject/mulfjxtx.html