美文网首页Android-Rxjava&retrofit&dagger
基于RxJava Retrofit的网络框架(一)

基于RxJava Retrofit的网络框架(一)

作者: 锅里的饽饽 | 来源:发表于2018-11-11 14:07 被阅读21次

    基于RxJava Retrofit网络框架的搭建

    RxJava、Retrofit两个第三方库的优势

    RxJava的使用场景

    本文讨论的如无特殊说明,均指代rxjava2 和 retrofit2。
    我们先讨论一下rxJava引入的背景。有一些应用场景,特别是一些复杂的异步回调场景,如果使用传统的开发模式,会如何实现。
    列举一些场景:

    1. EditText: 根据输入内容自动搜索时,只有当输入间隔大于某个duration时,才触发搜索。
      同时要根据输入内容,实时判断其有效性。
      对输入的内容,实时做出改变(比如不能输入数字,特殊字符等)
      https://www.jianshu.com/p/9aaccd7bb600
    2. 联合判断
      https://www.jianshu.com/p/88ce90240396
    3. 注册--登录--获取用户信息(注册的一般流程) 获取权限--获取经纬度--鉴权--生成订单(生成订单一般流程) 这样一连串的网络请求。
    4. 结合多个接口的数据,再更新UI;或者历史记录、购物车记录等,需要合并本地缓存和网络请求返回的数据;
    5. 网络请求前置条件token的获取,token可以本地缓存,本地缓存拿不到要去网络获取。同时对于token拿不到时的网络请求先等待,token获取后将等待的请求一一发出。甚至token请求需要设置重试次数,超过次数才停止请求
    6. 防重复操作,倒计时
    7. 多重缓存处理:先读取缓存更新UI,在网络请求更新UI(https://www.jianshu.com/p/7474950af2df
    8. 多处场景需要同一个监听事件,但是每个场景注册时间点不同,如何做到事件产生之后注册的监听者也能收到回调。

    这些应用场景几乎是每个app都会遇到的,传统的处理方式:层层递进(回调),各种标志位控制,嵌套的if else,各种异步调用分散在代码各处,要将各个回调结果汇总,并且综合处理回调的不同状态。而且由于异步回调的特点,代码处理方式不会像同步调用那样直接可控,异步回调导致的时序问题又将问题复杂度提高了几个level。我经常会想,这种callback的异步调用方式,为何会将代码变得丑陋不堪和难以维护?设计模式中只提供了观察者模式,但是对于观察者回调复杂后,没有提出更好的解决方案。RxJava(或者说响应式编程)主要解决了这类的问题。
    关于RxJava是如何解决以上场景中遇到的问题,以及如何和retrofit一起联合使用,短短几行无法说不清,在基于RxJava Retrofit的网络框架(二)中会详解。

    Retrofit的使用

    Retrofit并不实现网络请求本身(网络请求由okhttp负责),他是一个框架,为网络请求本身提供可扩展,可配置,易使用的外部封装。okhttp负责提高网络请求的性能和兼容性,Retrofit负责更好的使用他。框架的重要性不言而喻,好的框架让使用者关注更少细节,轻易的扩展。okhttp好像汽车的发动机,对于汽车性能和稳定性起到决定性作用,框架就是除了发动机以外其他部分,除了对发送机功能的整合外,漂亮的外观,舒适易用的体验才是人们愿意开这台车的原因。
    以下列举Retrofit相对于volley Android-Async-Http等框架的优势

    1. 简洁易用:通过注解配置网络参数,大量设计模式(建造者模式,工厂)简化配置和使用。
    2. 功能强大:支持RxJava方式(也支持callback方式),支持同步&异步,
    3. 耦合度低,扩展性好:模块高度封装,彻底解耦。

    由于Android-Async-Http的停更,Google对volley基本放弃的态度,这两套框架使用者和价值日渐减少。反观okhttp,Google官方应用则广泛使用。作为okhttp的黄金搭档(同为square公司出品),Retrofit可以说是目前Android app网络请求框架的不二选择,与okhttp搭配,是性能、稳定性、兼容性、易用性都达到很高水平的框架组合。

    Observable网络框架的抽象

    Observable网络框架建立的原因

    1. Retrofit已经对网络请求做了封装,为什么还要封装?
      网络请求中对于请求流程、配置、加解密、异常处理对于每个app都是固定不变的,如果业务每次请求都自己处理逻辑,会存在冗余代码,且质量不易保证。所以我们需要基于Retrofit对请求流程、配置、加解密、异常处理等操作做二次封装,并对调用方式进行统一。
    2. 框架封装方式Observable是什么?
      对网络请求二次封装(一般为异步请求),传统使用callback方式异步回调网络请求结果。但是这种callback的方式,没有利用到Retrofit的一大优势--rxjava调用,所以我们要基于rxjava调用方式,封装一个基于Observable的网络请求框架。
      以下所说网络框架,均指基于Observable的网络请求二次封装框架。

    Observable网络框架要解决的问题

    网络框架要帮助业务处理以下几个问题:

    1. 支持Get Post请求,对Request的参数业务可轻松配置
    2. 对Request 参数做发送前处理:组合和加密处理
    3. 返回Response 解密处理,Java实体化
    4. 返回Response code码判断及处理
    5. 网络请求cancle机制 progressBar配置等通用处理
      达到的目标:业务使用框架时,只需要关注业务相关(Request参数,Response返回值的配置和处理),其他都交给框架处理。同时对于网络请求的属性可配置(error是否提示,progressBar是否显示等)

    Observable网络框架如何实现

    设计原则:

    1. 网络请求Api返回Observable对象,作为网络请求事件的生产者:
      生产者负责请求的发起,和返回的所有预处理。
    2. 为业务提供BaseObserver类,使用者实现其子类作为消费者
      消费者基类提供对response的一般处理,消费者业务也可以使用自己Observer处理

    在Observable的创建过程中,框架如何封装?

    首先我们需要一个Manager或Helper全局实例,通过他可以发起网络请求,一般设计为单例全局持有,有利于网络请求一些资源的共用。
    我们暂定为NetHelper,其网络请求接口定义为:

    private static Observable<R> sendRequest(final HttpRequest request, final TypeReference<R> t)
    

    sendRequest方法中,我们来看下Observable对象的生成过程:此处我们基于Retrofit本身Observable生成方式,我们先看下Retrofit最基础是如何创建Observable的。

    第一步,定义Request,Request类的定义在Retrofit里通过注解的方式完成的

    public interface Request {
    
        @POST("{url}")
        Observable<JSONObject> postJSONResult(@Path(value="url",encoded =true) String url, @FieldMap Map<String, String> params);
    }
    
    

    可以看到我们的定义方式是通用的(每个request都可以复用),每个request都是通过postJSONResult方法获取observable,传入自己的url和params即可完成不同的网络请求。

    第二步,创建retrofit
    NetHelper.java中

    // 初始化okhttp
    OkHttpClient client = new OkHttpClient.Builder()
            .build();
    
    // 初始化Retrofit
    retrofit = new Retrofit.Builder()
            .client(client)
            .baseUrl(Request.HOST)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(MyConverterFactory.create())
            .build();
    
    

    OkHttpClient每次请求的时候都要创建,注意:OkHttpClient.Builder()中有ConnectionPool作为OkHttp的连接池要复用,否则请求过多时容易导致内存溢出。
    创建Retrofit实例过程中,设置了okHttpClient,baseUrl,调用方式rxJava(通过addCallAdapterFactory)
    GsonConverterFactory这些都是一般的写法,GsonConverterFactory作用是把Response通过GSon转为javaBean。App业务中一般是先解密后Gson转,所以此处使用MyConverterFactory实现解密功能。

    第三步,生成Observable
    这一步是生成observable的过程,与httpRequest本身有关(我们前面提到了Request类是一个支持Retrofit通用类,业务自定义的请求类HttpRequest实现了 getURLParam() getURLAction()等方法),所以这个获取Observable的方法可以放到HttpRequest中进行(NetHelper.sendRequest方法是传入了HttpRequest对象的)

    Request request = retrofit.create(Request.class);
    return request.postJSONResult(getURLAction(),getURLParam());
    

    对于httpRequest中入参的组合和加密,实现在getURLParam()方法里。
    备注:我们的网络post请求params是query形式的,如果是body表单,还需要另外的处理方式。

    以上三步,已经初步将Observable返回。通过以上几步只是基于Retrofit自身的Observable创建方法做了一些封装。下面的处理是框架的重点和核心:

    private static Observable<R> sendRequest(final HttpRequest request,final TypeReference<R> t){
    
            return NetHelper.getApiObservable(request)
                    .compose(ResponseTransformer.handleResult())
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread());
    
        }
    

    注意:sendRequest方法一定要Observable所有的链式操作执行完后在返回。


    NetHelper.getApiObservable方法后,再加上网络请求的线程配置,这时候业务subscribe消费者,就可以直接得到解密后的JsonObject了。注意此时是string而不是Retrofit通常的JavaBean,这是因为我们要定义一个通用的Request类,将其接口返回值定义为了Observable<JSONObject>,所以我们还需要一步转换。

        .map(new Function<JSONObject,R>() {
            @Override
            public R apply(JSONObject jsonObject) throws Exception {
                if (jsonObject != null){
                    R response = jsonObject.toJavaObject(con);
                    if (orgRequest != null) {
                        HttpHelper.printHttpLog(orgRequest, jsonObject.toString());
                    }
                    return response;
                } else {
                    return null;
                }
            }
        })
    

    response的异常处理,progressbar的显示等,也需要架构统一处理。我们引入了ResponseTransformer,你可以把他理解为map操作符,在交给消费者前对response结果做了处理。

    public static <T extends Serializable> ObservableTransformer<T, T> handleResult() {
        return upstream -> upstream
                .onErrorResumeNext(new ErrorResumeFunction<T>())
                .flatMap(new ResponseFunction<T>());
    }
    
    private static class ErrorResumeFunction<T extends Serializable> implements Function<Throwable, ObservableSource<? extends T>> {
    
        @Override
        public ObservableSource<? extends T> apply(Throwable throwable) throws Exception {
            return Observable.error(CustomException.handleException(throwable));
        }
    }
    
    private static class ResponseFunction<T extends Serializable> implements Function<T, ObservableSource<T>> {
    
        @Override
        public ObservableSource<T> apply(T tResponse) throws Exception {
            int code = tResponse.getCode();
            String message = tResponse.getMsg();
    
            if (code == SUCCESS.value()) {
                return Observable.just(tResponse);
            } else {
                return Observable.error(new ApiException(code, message));
            }
        }
    }
    

    可以看出对于事件流upstream,做了正常和异常的再分流,对于服务器错误(超时,404等)通过onErrorResumeFunction继续抛出Observable.error,
    对于正常返回,根据response中code的定义,只有SUCCESS时才返回数据Observable.just(),其他情况(业务错误等)作为错误情况继续抛出。
    你可能有两个疑问,一个是response中code的判定可以在observer中处理吗,另一个是服务器错误和业务错误为何都作为error抛出。

    第一个问题:
    code值的判定不可以在observer中处理,而必须在Observable一端处理。因为Observable形式的网络请求是作为数据流中的一环出现的,可能当前网络请求只是一连串异步调用(rxjava调用)的一环。
    第二个问题:
    response中code!=SUCCESS是业务错误的情况,必须向数据流中发出,让业务处理此异常。(那同时对于Response的定义也是,code!=SUCCESS必须是不需要业务处理的情况才行)
    两种错误都抛出error(内部code不同),方便架构使用者在事件响应时,既能捕捉所有错误,又能区分错误的类型。


    哪些处理放到了BaseObserver中?

    BaseObserver顾名思义,是架构使用者在rxjava流式调用最后一步所使用的观察者基类,他适合将网络请求的UI响应放入其中。

    public  abstract class   BaseObserver<T > implements Observer<T>{
      /**
        * 请求成功
        * @param t
        */
       public abstract void onSuccess(T t);
    
       /**
        * 请求失败
        * @param
        * @param object
        */
       public abstract void onFail(ApiException);
    
       @Override
        public void onSubscribe(Disposable d) {
            if (isShowProgress()) {
                showProgress(true);
            }
        }
    
        @Override
        public void onNext(T t) {
            if (isShowProgress()) {
                showProgress(false);
            }
            onSuccess(t);
        }
    
        @Override
        public void onError(Throwable e) {
          if (isShowProgress()) {
              showProgress(false);
          }
    
          if (e instanceof ApiException){
                ApiException apiException = (ApiException)e;
                switch(apiException.getCode()){
                  case:NOT_LOGIN
                    break;
                  case:TOKEN_ERROR
                    break;
                }
          }
        }
    
        /**
         * 网络请求是否loading显示
         * @return
         */
        protected boolean isShowProgress(){
            return true;
        }
    }
    

    BaseObserver中,我们可以看到处理了showProgress,ApiException做了处理。同时可以对progressBar是否显示做配置。可以满足一般的网络请求架构使用,当然也可以自行subscribe自己的Observer。

    相关文章

      网友评论

        本文标题:基于RxJava Retrofit的网络框架(一)

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