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

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

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

    封装成果

    封装完以后,具有如下功能:

        1.Retrofit+Rxjava+okhttp基本使用方法
        2.统一处理请求数据格式
        3.统一的ProgressDialog和回调Subscriber处理
        4.取消http请求
        5.预处理http请求
        6.返回数据的统一判断
        7.失败后的retry封装处理
        8.RxLifecycle管理生命周期,防止泄露
    

    效果:

    ebcee353719368ac7f7a7c3c93cad854.gif
    具体使用:

    封装后http请求代码如下

    //    完美封装简化版
        private void simpleDo() {
            SubjectPost postEntity = new SubjectPost(simpleOnNextListener,this);
            postEntity.setAll(true);
            HttpManager manager = HttpManager.getInstance();
            manager.doHttpDeal(postEntity);
        }
    
        //   回调一一对应
        HttpOnNextListener simpleOnNextListener = new HttpOnNextListener<List<Subject>>() {
            @Override
            public void onNext(List<Subject> subjects) {
                tvMsg.setText("已封装:\n" + subjects.toString());
            }
    
            /*用户主动调用,默认是不需要覆写该方法*/
            @Override
            public void onError(Throwable e) {
                super.onError(e);
                tvMsg.setText("失败:\n" + e.toString());
            }
        };
    

    是不是很简单?你可能说这还简单,好咱们对比一下正常使用Retrofit的方法

    /**  
        * Retrofit加入rxjava实现http请求  
        */  
       private void onButton9Click() {  
           //手动创建一个OkHttpClient并设置超时时间  
           okhttp3.OkHttpClient.Builder builder = new OkHttpClient.Builder();  
           builder.connectTimeout(5, TimeUnit.SECONDS);  
    
           Retrofit retrofit = new Retrofit.Builder()  
                   .client(builder.build())  
                   .addConverterFactory(GsonConverterFactory.create())  
                   .addCallAdapterFactory(RxJavaCallAdapterFactory.create())  
                   .baseUrl(HttpManager.BASE_URL)  
                   .build();  
    
    /        加载框  
           final ProgressDialog pd = new ProgressDialog(this);  
    
           HttpService apiService = retrofit.create(HttpService.class);  
           Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true);  
           observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())  
                   .subscribe(  
                           new Subscriber<RetrofitEntity>() {  
                               @Override  
                               public void onCompleted() {  
                                   if (pd != null && pd.isShowing()) {  
                                       pd.dismiss();  
                                   }  
                               }  
    
                               @Override  
                               public void onError(Throwable e) {  
                                   if (pd != null && pd.isShowing()) {  
                                       pd.dismiss();  
                                   }  
                               }  
    
                               @Override  
                               public void onNext(RetrofitEntity retrofitEntity) {  
                                   tvMsg.setText("无封装:\n" + retrofitEntity.getData().toString());  
                               }  
    
                               @Override  
                               public void onStart() {  
                                   super.onStart();  
                                   pd.show();  
                               }  
                           }  
    
                   );  
       }
    

    可能你发现确是代码有点多,但是更加可怕的是,如果你一个activity或者fragment中多次需要http请求,你需要多次重复的写回调处理(一个回到就有4个方法呀!!!!反正我是忍受不了),而且以上处理还没有做过多的判断和错误校验就如此复杂!~好了介绍完了,开始咱们的优化之路吧!


    项目结构:
    03184db20dc2b7b159d4.png

    RxJava

    如果你对RxJava不了解,好吧骚年赶快学学吧,不然真会out了,下面给出博主当初学习RxJava的一些资源:

    Retrofit

    咱家今天的主角来了,咱们也深入浅出一下了解下Retrofit使用,前方高能,如果你是深度Retrofit选手请直接跳过本节!!!

    1.首先确保在AndroidManifest.xml中请求了网络权限

    <uses-permission android:name="android.permission.INTERNET"/>

    2.在app/build.gradle添加引用
        /*rx-android-java*/
        compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
        compile 'com.trello:rxlifecycle:1.0'
        compile 'com.trello:rxlifecycle-components:1.0'
        /*rotrofit*/
        compile 'com.squareup.retrofit2:retrofit:2.1.0'
        compile 'com.squareup.retrofit2:converter-gson:2.0.0'
        compile 'com.google.code.gson:gson:2.8.0'
    
    3.常用注解

    这里介绍一些常用的注解的使用

    • @Query@QueryMap:用于Http Get请求传递参数
    • @Field:用于Post方式传递参数,需要在请求接口方法上添加@FormUrlEncoded,即以表单的方式传递参数
    • @Body:用于Post,根据转换方式将实例对象转化为对应字符串传递参数.比如Retrofit添加GsonConverterFactory则是将body转化为gson字符串进行传递
    • @Path:用于URL上占位符
    • @Part:配合@Multipart使用,一般用于文件上传
    • @Header:添加http header
    • @Headers:跟@Header作用一样,只是使用方式不一样,@Header是作为请求方法的参数传入,@Headers是以固定方式直接添加到请求方法上
    ReTrofit基本使用:

    首先给定一个测试接口文档,后面的博客中我们都是用这个接口调试

    /**  
     * @api    videoLink    50音图视频链接  
     * @url    http://www.izaodao.com/Api/AppFiftyToneGraph/videoLink  
     * @method post  
     * @param  once_no bool(选填,ture无链接) 一次性获取下载地址  
     * @return json array(  
     * ret:1成功,2失败  
     * msg:信息  
     * data:{  
     *       name:视频名称  
     *       title:标题  
     * }  
     *)
     **/
    
    1.初始化retrofit

    要向一个api发送我们的网络请求 ,我们需要使用Retrofit builder类并指定service的base URL(通常情况下就是域名)。

    String BASE_URL = " http://www.izaodao.com/Api/"  
        Retrofit retrofit = new Retrofit.Builder()  
                .baseUrl(BASE_URL)  
                .addConverterFactory(GsonConverterFactory.create())  
                .build();
    
    2.设置接口service

    注意到每个endpoint都指定了一个关于HTTP(GET, POST, 等等。) 方法的注解以及用于分发网络调用的方法。而且这些方法的参数也可以有特殊的注解。

    /**  
     * 接口地址  
     * Created by WZG on 2016/7/16.  
     */  
    public interface MyApiEndpointInterface {  
        @POST("AppFiftyToneGraph/videoLink")  
        Call<RetrofitEntity> getAllVedio(@Body boolean once_no)             
    }
    
    3.得到call然后同步处理处理回调:
    MyApiEndpointInterface apiService = retrofit.create(MyApiEndpointInterface.class);  
    Call<RetrofitEntity> call = apiService.getAllVedio(true);  
    call.enqueue(new Callback<RetrofitEntity>() {  
        @Override  
        public void onResponse(Response<RetrofitEntity> response, Retrofit retrofit) {  
            RetrofitEntity entity = response.body();  
            Log.i("tag", "onResponse----->" + entity.getMsg());  
        }  
    
        @Override  
        public void onFailure(Throwable t) {  
            Log.i("tag", "onFailure----->" + t.toString());  
    
        }  
    });
    

    这就是简单的Retrofit使用步骤,接下来我们结合RxJava讲述

    ReTrofit+Rxjava基本使用

    对比之前的Retrofit使用

    1.在于我们需要修改service接口返回信息我们需要返回一个Observable对象
    @POST("AppFiftyToneGraph/videoLink")  
    Observable<RetrofitEntity> getAllVedioBy(@Body boolean once_no);
    
    2.然后初始化Retrofit需要添加对Rxjava的适配,注意一定要retrofit2才有这个功能哦
    Retrofit retrofit = new Retrofit.Builder()  
                    .client(builder.build())  
                    .addConverterFactory(GsonConverterFactory.create())  
                   .addCallAdapterFactory(RxJavaCallAdapterFactory.create())  
                    .baseUrl(HttpManager.BASE_URL)  
                    .build();
    
    3.回调通过RxJava处理
    HttpService apiService = retrofit.create(HttpService.class);  
           Observable<RetrofitEntity> observable = apiService.getAllVedioBy(true);  
           observable.subscribeOn(Schedulers.io()).unsubscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())  
                   .subscribe(  
                           new Subscriber<RetrofitEntity>() {  
                               @Override  
                               public void onCompleted() {  
                               }  
    
                               @Override  
                               public void onError(Throwable e) {                                
                               }  
    
                               @Override  
                               public void onNext(RetrofitEntity retrofitEntity) {  
                                   tvMsg.setText("无封装:\n" + retrofitEntity.getData().toString());  
                               }                            
                           }  
    
                   );
    

    简单的RxJava集合Retrofit的使用就介绍完了,同样的可以发现使用起来很多重复性的代码,而且使用也不是那么简单,所以才有了下面的封装

    ReTrofit+Rxjava进阶封装之路

    先来一张流程图压压惊

    17c55b03c9b9d8e99ff07dbe611f285b.png
    请求数据封装
    1.参数

    首先需要封装的使我们的数据类,在数据类中需要封装请求中用到的相关数据的设置,比如请求参数、方法、加载框显示设置等等

    public abstract class BaseApi<T> implements Func1<BaseResultEntity<T>, T> {
        //rx生命周期管理
        private SoftReference<RxAppCompatActivity> rxAppCompatActivity;
        /*回调*/
        private SoftReference<HttpOnNextListener> listener;
        /*是否能取消加载框*/
        private boolean cancel;
        /*是否显示加载框*/
        private boolean showProgress;
        /*是否需要缓存处理*/
        private boolean cache;
        /*基础url*/
        private  String baseUrl="http://www.izaodao.com/Api/";
        /*方法-如果需要缓存必须设置这个参数;不需要不用設置*/
        private String mothed;
        /*超时时间-默认6秒*/
        private int connectionTime = 6;
        /*有网情况下的本地缓存时间默认60秒*/
        private int cookieNetWorkTime=60;
        /*无网络的情况下本地缓存时间默认30天*/
        private int cookieNoNetWorkTime=24*60*60*30;
    }
    

    注释很详细,这里不具体描述了,由于这里是最后封装完成以后的代码,所以有些内容本章还会部分不会涉及,因为功能太多,还是按照一开始的博客章节讲解。

    2.抽象api接口
    /**
         * 设置参数
         *
         * @param retrofit
         * @return
         */
        public abstract Observable getObservable(Retrofit retrofit);
    

    通过子类也即是我们的具体api接口,通过getObservable实现service中定义的接口方法,例如:

    public class SubjectPostApi extends BaseApi {
         xxxxxxx
         xxxxxxx
    
     @Override
        public Observable getObservable(Retrofit retrofit) {
            HttpPostService service = retrofit.create(HttpPostService.class);
            return service.getAllVedioBys(isAll());
        }
    }
    

    通过传入的Retrofit对象,可以随意切换挑选Service对象,得到定义的注解方法,初始完成以后返回Observable对象。

    3.结果判断

    这里结合RxJava的map方法在服务器返回数据中,统一处理数据处理,所以BaseApi<T> implements Func1<BaseResultEntity<T>, T>,后边结合结果处理链接起来使用

    @Override
        public T call(BaseResultEntity<T> httpResult) {
            if (httpResult.getRet() == 0) {
                throw new HttpTimeException(httpResult.getMsg());
            }
            return httpResult.getData();
        }
    

    由于测试接口,也是当前我们公司接口都是有统一规则的,想必大家都有这样的接口规则,所以才有这里的统一判断,规则如下:

    * ret:1成功,2失败  
     * msg:信息  
     * data:{  
     *       name:视频名称  
     *       title:标题  
     * }
    

    其实上面的接口文档中就介绍了,统一先通过ret判断,失败显示msg信息,data是成功后的数据也就是用户关心的数据,所以可封装一个结果对象BaseResultEntity.

    4.结果数据
    /**
     * 回调信息统一封装类
     * Created by WZG on 2016/7/16.
     */
    public class BaseResultEntity<T> {
        //  判断标示
        private int ret;
        //    提示信息
        private String msg;
        //显示数据(用户需要关心的数据)
        private T data;
    
    
        xxxxx  get-set  xxxxx
    }
    

    这里结合BaseApi的Func1判断,失败直接抛出一个异常,交个RxJava的onError处理,成功则将用户关心的数据传给Gson解析返回

    5.泛型传递

    BaseResultEntity<T>中的泛型T也就是我们所关心的回调数据,同样也是Gson最后解析返回的数据,传递的过程根节点是通过定义service方法是给定的,例如:

    public interface HttpPostService {
        @POST("AppFiftyToneGraph/videoLink")
        Call<RetrofitEntity> getAllVedio(@Body boolean once_no);
    }
    

    其中的RetrofitEntity就是用户关心的数据类,通过泛型传递给最后的接口。

    6.强调

    很多兄弟通过QQ群反馈给我说,使用一个接口需要写一个对应的api类继承BaseApi是不是很麻烦,我这里强调一下,这样封装是为了将一个Api接口作为一个对象去封装,个人觉得有必要封装成一个类,在日后工程日益增加接口随着增加的同时,对象的做法更加有利于查找接口和修改接口有利于迭代。


    操作类封装
    1初始对象

    首先初始化一个单利方便HttpManager请求;这里用了volatile的对象,不懂的同学可以参考我的另一篇博客

    你真的会写单例吗?

      private volatile static HttpManager INSTANCE;
    
        //构造方法私有
        private HttpManager() {
        }
    
        //获取单例
        public static HttpManager getInstance() {
            if (INSTANCE == null) {
                synchronized (HttpManager.class) {
                    if (INSTANCE == null) {
                        INSTANCE = new HttpManager();
                    }
                }
            }
            return INSTANCE;
        }
    
    2接口处理和回调处理:
     /**
         * 处理http请求
         *
         * @param basePar 封装的请求数据
         */
        public void doHttpDeal(BaseApi basePar) {
            //手动创建一个OkHttpClient并设置超时时间缓存等设置
            OkHttpClient.Builder builder = new OkHttpClient.Builder();
            builder.connectTimeout(basePar.getConnectionTime(), TimeUnit.SECONDS);
            builder.addInterceptor(new CookieInterceptor(basePar.isCache()));
    
            /*创建retrofit对象*/
            Retrofit retrofit = new Retrofit.Builder()
                    .client(builder.build())
                    .addConverterFactory(GsonConverterFactory.create())
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
                    .baseUrl(basePar.getBaseUrl())
                    .build();
    
    
            /*rx处理*/
            ProgressSubscriber subscriber = new ProgressSubscriber(basePar);
            Observable observable = basePar.getObservable(retrofit)
                    /*失败后的retry配置*/
                    .retryWhen(new RetryWhenNetworkException())
                    /*生命周期管理*/
                    .compose(basePar.getRxAppCompatActivity().bindToLifecycle())
                    /*http请求线程*/
                    .subscribeOn(Schedulers.io())
                    .unsubscribeOn(Schedulers.io())
                    /*回调线程*/
                    .observeOn(AndroidSchedulers.mainThread())
                    /*结果判断*/
                    .map(basePar);
    
            /*数据回调*/
            observable.subscribe(subscriber);
        }
    

    首先通过api接口类BaseApi的实现类中数据初始化OkHttpClient和Retrofit对象,其中包含了url,超时等,接着通过BaseApi的抽象方法getObservable得到Observable对象,得到Observable对象以后,我们就能随意的切换现成来处理,整个请求通过compose设定的rxlifecycle来管理生命周期,所以不会溢出和泄露无需任何担心,最后再服务器数据返回时,通过map判断结果,剔除错误信息,成功以后返回到自定义的ProgressSubscriber对象中,所以接下来封装ProgressSubscriber对象。

    ProgressSubscriber封装

    • onStart():开始
    • onCompleted():结束
    • onError(Throwable e):错误
    • onNext(T t):成功
    1.请求加载框

    http请求都伴随着加载框的使用,所以这里需要在onStart()使用前初始一个加载框,这里简单的用ProgressDialog代替

    /**
     * 用于在Http请求开始时,自动显示一个ProgressDialog
     * 在Http请求结束是,关闭ProgressDialog
     * 调用者自己对请求数据进行处理
     * Created by WZG on 2016/7/16.
     */
    public class ProgressSubscriber<T> extends Subscriber<T> {
        /*是否弹框*/
        private boolean showPorgress = true;
        /* 软引用回调接口*/
        private SoftReference<HttpOnNextListener> mSubscriberOnNextListener;
        /*软引用反正内存泄露*/
        private SoftReference<RxAppCompatActivity> mActivity;
        /*加载框可自己定义*/
        private ProgressDialog pd;
        /*请求数据*/
        private BaseApi api;
    
    
        /**
         * 构造
         *
         * @param api
         */
        public ProgressSubscriber(BaseApi api) {
            this.api = api;
            this.mSubscriberOnNextListener = api.getListener();
            this.mActivity = new SoftReference<>(api.getRxAppCompatActivity());
            setShowPorgress(api.isShowProgress());
            if (api.isShowProgress()) {
                initProgressDialog(api.isCancel());
            }
        }
    
    
        /**
         * 初始化加载框
         */
        private void initProgressDialog(boolean cancel) {
            Context context = mActivity.get();
            if (pd == null && context != null) {
                pd = new ProgressDialog(context);
                pd.setCancelable(cancel);
                if (cancel) {
                    pd.setOnCancelListener(new DialogInterface.OnCancelListener() {
                        @Override
                        public void onCancel(DialogInterface dialogInterface) {
                            onCancelProgress();
                        }
                    });
                }
            }
        }
    
    
        /**
         * 显示加载框
         */
        private void showProgressDialog() {
            if (!isShowPorgress()) return;
            Context context = mActivity.get();
            if (pd == null || context == null) return;
            if (!pd.isShowing()) {
                pd.show();
            }
        }
    
    
        /**
         * 隐藏
         */
        private void dismissProgressDialog() {
            if (!isShowPorgress()) return;
            if (pd != null && pd.isShowing()) {
                pd.dismiss();
            }
        }
    }
    

    由于progress的特殊性,需要指定content而且不能是Application所以这里传递一个RxAppCompatActivity,而同时上面的HttpManager同样需要,所以这里统一还是按照BaseApi传递过来,使用软引用的方式避免泄露。剩下的无非是初始化,显示和关闭方法,可以详细看代码。

    2.onStart()实现

    在onStart()中需要调用加载框,然后这里还有网络缓存的逻辑,后面会单独讲解,现在先忽略它的存在。

     /**
         * 订阅开始时调用
         * 显示ProgressDialog
         */
        @Override
        public void onStart() {
            showProgressDialog();
            /*缓存并且有网*/
            if (api.isCache() && AppUtil.isNetworkAvailable(RxRetrofitApp.getApplication())) {
                 /*获取缓存数据*/
                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();
                    }
                }
            }
        }
    
    3.onCompleted()实现
     /**
         * 完成,隐藏ProgressDialog
         */
        @Override
        public void onCompleted() {
            dismissProgressDialog();
        }
    
    4.onError(Throwable e)实现

    在onError(Throwable e)是对错误信息的处理和缓存读取的处理,后续会讲解,先忽略。

    /**
         * 对错误进行统一处理
         * 隐藏ProgressDialog
         *
         * @param e
         */
        @Override
        public void onError(Throwable e) {
            dismissProgressDialog();
            /*需要緩存并且本地有缓存才返回*/
            if (api.isCache()) {
                Observable.just(api.getUrl()).subscribe(new Subscriber<String>() {
                    @Override
                    public void onCompleted() {
    
                    }
    
                    @Override
                    public void onError(Throwable e) {
                        errorDo(e);
                    }
    
                    @Override
                    public void onNext(String s) {
                        /*获取缓存数据*/
                        CookieResulte cookieResulte = CookieDbUtil.getInstance().queryCookieBy(s);
                        if (cookieResulte == null) {
                            throw new HttpTimeException("网络错误");
                        }
                        long time = (System.currentTimeMillis() - cookieResulte.getTime()) / 1000;
                        if (time < api.getCookieNoNetWorkTime()) {
                            if (mSubscriberOnNextListener.get() != null) {
                                mSubscriberOnNextListener.get().onCacheNext(cookieResulte.getResulte());
                            }
                        } else {
                            CookieDbUtil.getInstance().deleteCookie(cookieResulte);
                            throw new HttpTimeException("网络错误");
                        }
                    }
                });
            } else {
                errorDo(e);
            }
        }
    
        /*错误统一处理*/
        private void errorDo(Throwable e) {
            Context context = mActivity.get();
            if (context == null) return;
            if (e instanceof SocketTimeoutException) {
                Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show();
            } else if (e instanceof ConnectException) {
                Toast.makeText(context, "网络中断,请检查您的网络状态", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "错误" + e.getMessage(), Toast.LENGTH_SHORT).show();
            }
            if (mSubscriberOnNextListener.get() != null) {
                mSubscriberOnNextListener.get().onError(e);
            }
        }
    
    5.onNext(T t)实现
      /**
         * 将onNext方法中的返回结果交给Activity或Fragment自己处理
         *
         * @param t 创建Subscriber时的泛型类型
         */
        @Override
        public void onNext(T t) {
            if (mSubscriberOnNextListener.get() != null) {
                mSubscriberOnNextListener.get().onNext(t);
            }
        }
    

    主要是是将得到的结果,通过自定义的接口返回给view界面,其中的软引用对象mSubscriberOnNextListener是自定义的接口回调类HttpOnNextListener.

    6.HttpOnNextListener封装

    现在只需关心onNext(T t)onError(Throwable e)接口即可,回调的触发点都是在上面的ProgressSubscriber中调用

    /**
     * 成功回调处理
     * Created by WZG on 2016/7/16.
     */
    public abstract class HttpOnNextListener<T> {
        /**
         * 成功后回调方法
         * @param t
         */
        public abstract void onNext(T t);
    
        /**
         * 緩存回調結果
         * @param string
         */
        public void onCacheNext(String string){
    
        }
    
        /**
         * 失败或者错误方法
         * 主动调用,更加灵活
         * @param e
         */
        public  void onError(Throwable e){
    
        }
    
        /**
         * 取消回調
         */
        public void onCancel(){
    
        }
    }
    

    失败后的retry处理

    这里你可能会问,Retrofit有自带的retry处理呀,的确Retrofit有自带的retry处理,但是有很多的局限,先看下使用

    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    builder.retryOnConnectionFailure(true);
    

    使用起来还是很方便,只需要调用一个方法即可,但是它是不可控的,也就是没有办法设置retry时间次数,所以不太灵活,既然如此还不如自己封装一下,因为用RxJava实现这个简直小菜,无形中好像已经给RxJava打了广告,中毒太深。
    很简单直接上代码:

    /**
     * retry条件
     * Created by WZG on 2016/10/17.
     */
    public class RetryWhenNetworkException implements Func1<Observable<? extends Throwable>, Observable<?>> {
    //    retry次数
        private int count = 3;
    //    延迟
        private long delay = 3000;
    //    叠加延迟
        private long increaseDelay = 3000;
    
        public RetryWhenNetworkException() {
    
        }
    
        public RetryWhenNetworkException(int count, long delay) {
            this.count = count;
            this.delay = delay;
        }
    
        public RetryWhenNetworkException(int count, long delay, long increaseDelay) {
            this.count = count;
            this.delay = delay;
            this.increaseDelay = increaseDelay;
        }
    
        @Override
        public Observable<?> call(Observable<? extends Throwable> observable) {
            return observable
                    .zipWith(Observable.range(1, count + 1), new Func2<Throwable, Integer, Wrapper>() {
                        @Override
                        public Wrapper call(Throwable throwable, Integer integer) {
                            return new Wrapper(throwable, integer);
                        }
                    }).flatMap(new Func1<Wrapper, Observable<?>>() {
                        @Override
                        public Observable<?> call(Wrapper wrapper) {
                            if ((wrapper.throwable instanceof ConnectException
                                    || wrapper.throwable instanceof SocketTimeoutException
                                    || wrapper.throwable instanceof TimeoutException)
                                    && wrapper.index < count + 1) { //如果超出重试次数也抛出错误,否则默认是会进入onCompleted
                                return Observable.timer(delay + (wrapper.index - 1) * increaseDelay, TimeUnit.MILLISECONDS);
    
                            }
                            return Observable.error(wrapper.throwable);
                        }
                    });
        }
    
        private class Wrapper {
            private int index;
            private Throwable throwable;
    
            public Wrapper(Throwable throwable, int index) {
                this.index = index;
                this.throwable = throwable;
            }
        }
    }
    

    使用

    到这里,我们第一步封装已经完成了,下面讲解下如何使用,已经看明白的各位看官,估计早就看明白了使用方式,无非是创建一个api对象继承BaseApi初始接口信息,然后调用HttpManager对象的doHttpDeal(BaseApi basePar)方法,最后静静的等待回调类HttpOnNextListener<T>类返回的onNext(T t)成功数据或者onError(Throwable e)数据。
    其实代码就是这样:

    api接口对象
    /**
     * 测试数据
     * Created by WZG on 2016/7/16.
     */
    public class SubjectPostApi extends BaseApi {
    //    接口需要传入的参数 可自定义不同类型
        private boolean all;
        /*任何你先要传递的参数*/
    //    String xxxxx;
    
        /**
         * 默认初始化需要给定回调和rx周期类
         * 可以额外设置请求设置加载框显示,回调等(可扩展)
         * @param listener
         * @param rxAppCompatActivity
         */
        public SubjectPostApi(HttpOnNextListener listener, RxAppCompatActivity rxAppCompatActivity) {
            super(listener,rxAppCompatActivity);
            setShowProgress(true);
            setCancel(true);
            setCache(true);
            setMothed("AppFiftyToneGraph/videoLink");
            setCookieNetWorkTime(60);
            setCookieNoNetWorkTime(24*60*60);
        }
    
        public boolean isAll() {
            return all;
        }
    
        public void setAll(boolean all) {
            this.all = all;
        }
    
        @Override
        public Observable getObservable(Retrofit retrofit) {
            HttpPostService service = retrofit.create(HttpPostService.class);
            return service.getAllVedioBys(isAll());
        }
    }
    
    请求回调
    
        //    完美封装简化版
        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("取消請求");
            }
        };
    

    后续

    到这里,封装功能中很多功能还没涉及和讲解,后续会陆续更新!
    先给大家看看为师的完全体功能:

        1.Retrofit+Rxjava+okhttp基本使用方法
        2.统一处理请求数据格式
        3.统一的ProgressDialog和回调Subscriber处理
        4.取消http请求
        5.预处理http请求
        6.返回数据的统一判断
        7.失败后的retry处理
        8.RxLifecycle管理生命周期,防止泄露
        9.文件上传下载(支持多文件,断点续传)
        10.Cache数据持久化和数据库(greenDao)两种缓存机制
        11.异常统一处理
    

    来个图压压惊:

    392c43f0540bbac7f2fc093566aed53d.gif
    迫不及待的小伙伴可以看这里:

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


    源码:

    RxRetrofit-终极封装-深入浅出&网络请求-GitHub
    其实我还有一个兄弟版本-传送门
    我会告诉你其实我还有个更加简单的版本

    相关文章

      网友评论

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

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