Android的网络请求框架

前言

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

搭建说明

整体的流程大致是这样:

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

如果分层的话,大致是:

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

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

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

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

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

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

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

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

《Android的网络请求框架》

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个拦截动作,如下图:

《Android的网络请求框架》

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

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;
}

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

《Android的网络请求框架》

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();
}

好吧,就介绍到这。

    原文作者:维少
    原文地址: https://www.jianshu.com/p/f1569186511c
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞