Android的网络请求框架

作者: 747a945a4501 | 来源:发表于2016-05-06 20:30 被阅读916次

    前言


    现在很多的app都是依赖网络服务的应用。跟服务器通讯我们就要用到网络请求。网络请求的框架有很多:原生自己封装的,Volley,OKHttp,Spring for android,Retrofit...等等。当然今天不讨论这些框架的使用或者好处,而是讨论网络服务的app的框架要如何搭建。

    搭建说明


    整体的流程大致是这样:

    用户操作->业务处理->网络请求->数据解析->业务处理->界面改变。

    如果分层的话,大致是:

    视图层 -> 业务处理层 -> 网络请求层

    那咱们还得弄清楚一些原则:

    • 既然分层了,咱们首先要搞清楚每一层该做什么事情。

    视图层: 跟用户交互以及界面展示方面的,例如请求弹出个进度框,请求成功或者失败要通知用户,界面刷新展示,用户体验就靠这层了。
    业务处理层:请求数据装载 (例如:登录 Basic Auth,视图层提供输入框里面的用户名和密码, 这里转化成服务器识别的参数要求),业务处理,得到网络请求返回的数据处理 (例如:缓存, 校验等)
    **网络请求层: **就是调用各个框架请求网络,负责和服务器交互

    那检查手机网络应该放在那一层呢?我这里就不说了。

    • 表层可以依赖底层,底层不能依赖表层。
    • 不要跨层依赖。
    • 层与层的依赖关系要尽量减少耦合

    这个得自己用其他框架实现,依赖注入,代理,事件总线,Base基类等等,今天就不讨论这个。

    讲到这,其实咱们的框架是这样的:



    1~6的过程中,可能有些步骤是耗时,且在不同的线程中执行。但是他们的步奏是一定是1-6顺序执行完。
    当然上面是顺利的流程,当然也有可能出现其他的情况,1~6的过程中取消任务或者出现异常。

    ok,那我们下面来讨论下不正常的情况

    • 执行过程取消任务,我们的框架应该是支持任一过程中取消任务执行。

    取消任务触发条件可能是用户操作或者页面退出等,那任务就没有必要执行下去,就要取消。达到的效果就是任一点取消任务,后面的过程将不会执行,这里的3,4可能是线程执行的过程,如果有可能可以中断线程。

    • 异常处理

    每一个过程都要可能产生异常,异常处理原则就交给有能力处理的层去处理,例如网络异常一般都是抛到UI层,然后提示用户。

    代码实现


    讨论那么多,那代码如何实现呢?我这边主要讲一下我的思路,如果有其他更好的方法,请告知。

    以前的思想是回调的方式,即底层执行的时候,需要调用者提供handler,就是实现回调接口。

    现在的思路是,就像滚雪球一样,底层给出核心的Excutor对象,往上抛,每经过一层,包上这一层的业务逻辑,由最外层执行操作。好处我觉得可扩展,代码优雅,低耦合。

    网络请求部分:

    我用的是 Retrofit + Rxjava,用OkHttp的Interceptor实现网络请求的切面编程,例如前面提到的Basic Auth等。

    public interface XXXDao {
    
      @GET("http://120.155.93.85:8080/rs/{name}")  
      Observable<List<Canteen>> getCanteen(@Path("name") String name, @Query("data") String date); 
    
       @GET("http://120.55.93.85:8080/rs/canteens")    
       Observable<retrofit2.Response<List<Canteen>>> getCanteen1();
    
    }
    

    比较简单吧,过程被框架封装了,这个咱们不管它,主要盯着它的返回,第一个小雪球: Observable<??>,它后面需要2个处理数据,Acton1<??>,Action<Throwable> 看名字就知道一个是处理异常的,一个是处理数据的。不懂的朋友看Rxjava.

    正常和异常都处理了,那如何在这一层取消任务呢?

    这里用的是Interceptor来拦截掉你要取消的任务。这里使用前后2个拦截动作,如下图:



    思路有了,如何代码实现呢?先看看拦截需要我们实现的代码

    public class XXXInterceptor implements Interceptor {    
    
        @Override    
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = judgeRequest(request);
            if(response == null){
                response = chain.proceed(request);
            }
            if(Response temp = judgeRequest(request) != null){
                response =  temp;
            }
            return response
        }
    
    
         private Response judgeRequest(Request request) {
            if(request 是否被取消){
                 return 异常的Response;
            }
            return null;
      }
    }
    

    拦截器是可以实现我们的效果,但是因为retrofit是支持取消任务的。上面的代码要做一丢丢的改变

    call.cancel();

    public interface XXXDao {
    
       @GET("http://120.155.93.85:8080/rs/{name}")  
       Call<List<Canteen>> getCanteen(@Path("name") String name, @Query("data") String date); 
    
        @GET("http://120.55.93.85:8080/rs/canteens")    
        Call<retrofit2.Response<List<Canteen>>> getCanteen1();
    
    }
    

    然后像上层抛出Call对象,当取消任务的时候,就调用cancel的方法,不过我这里没有对3,4做取消处理,因为我比较懒,闲麻烦。所以网络请求返回的还是Observable<??>对象。

    业务处理部分:
    小雪球拿到,我们就要在包装一下,像三明治一样,用2片面包包起来,其实就是前面做什么&后面做什么。

    public interface AppDao {    
    
      RestExcuter<List<Canteen>> getCanteen(String path, String date);  
    
      RestExcuter<Result<List<Canteen>>> getCanteen1();
    
    }
    

    我用RestExcuter来包装了Observable<??>,代码如下:

    private RestExcuter(@NonNull Observable<Bo> observable) {    
      super();    
      if (observable == null) {        
        throw new NullPointerException("Observable null !");   
       }    
       this.observable = observable;
    }
    

    然后提供了一些给上层调用的接口。


    errorDoing是交给视图层错误时候该做什么。
    postDoing是交给视图层成功了做什么。
    handler是交给视图层做动画处理的,例如某一个App请求网络的时候,是一个Gif图播放。

    public interface RestHandler<RestBo> { 
    
        /** 
        * 前面做什么
         */
        void pre();
    
        /**
         * 完成做什么
         * @param bo
         */
        void post(RestBo bo);
    
        /**
         * 异常做什么
         * @param throwable
         */
        void error(Throwable throwable);
    
    }
    

    下面是如何在这一层取消请求呢?

    //任务是否取消
    AtomicBoolean isCancel;
    
    boolean isCancel(){    
      boolean result = isCancel.get();    
      if (result) { 
           ZLog.i("任务已经被取消!");     
           if (errorDoing != null) {  
              errorDoing.call(new RestCancelException());  
          }   
       }   
       return result;
    }
    
    
    private void removeExcuter(){ 
       if(container != null){ 
           container.removeRestExcuter(this);
           container = null;    
           cancel();   
       }
    }
    
    /** * 取消任务 */
    public void cancel(){ 
       isCancel.compareAndSet(false,true);
    }
    
    /**
      * 请求的容器,例如activity在它销毁时候 取消这个容器下的所有请求
     */
    public interface RestContainer {    
    
        void addRestExcuter(RestExcuter<?> excuter);    
    
        void cancelAllRestExcuter();    
    
        void removeRestExcuter(RestExcuter<?> excuter);
    
    }
    

    isCancel是控制这个任务是否被取消。

    视图层
    视图层相对简单点,就是调用业务层,干自己改做的事情。代码如下:

    public void simpleClick(View view) {
        appDao.getCanteen("canteens", "2016-04-01")
                .setContainer(this)
                .handler(new DialogHandler<List<Canteen>>(this,"网络请求","正在请求网络,请稍等..."))
                .error(throwable -> binding.setInfo("请求出错啦"+throwable.getMessage()))
                .post(body -> setCanteenInfo(body))
                .excute();
    }
    

    好吧,就介绍到这。

    相关文章

      网友评论

        本文标题:Android的网络请求框架

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