OKHttp源码学习笔记:调用流程

基本用法

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
        .url(url)
        .post()
        .build();
Call call = okHttpClient.newCall(request);

//异步请求
call.enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: 异步请求失败 ");
    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {
        Log.d(TAG, "onResponse: 异步请求成功 " + response.body().string());
    }
});

//同步请求
Response  response = client.newCall(request).execute();//得到Response 对象(会阻塞当前线程)

跟到深处会发现无论同步和异步请求的关键都是拦截器方法

 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());
    interceptors.add(retryAndFollowUpInterceptor);
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    interceptors.add(new CacheInterceptor(client.internalCache()));
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    return chain.proceed(originalRequest);
  }

接下来就以该方法为入口分析下OkHttp3的代码

拦截器调用流程

再贴贴上面的代码分析一下

 //RealCall.Java
 Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 建立拦截器列表
    List<Interceptor> interceptors = new ArrayList<>();
    interceptors.addAll(client.interceptors());//自定义的拦截器,例如日志打印拦截器
    interceptors.add(retryAndFollowUpInterceptor);//重连及重定向拦截器
    interceptors.add(new BridgeInterceptor(client.cookieJar()));//桥拦截器?主要是用来加Header信息
    interceptors.add(new CacheInterceptor(client.internalCache()));//缓存拦截器
    interceptors.add(new ConnectInterceptor(client));//连接拦截器,用于建立连接
    if (!forWebSocket) {
      interceptors.addAll(client.networkInterceptors());//仅在建立WebSocket时才会加的拦截器
    }
    interceptors.add(new CallServerInterceptor(forWebSocket));//发送信息拦截器(之前的连接拦截器负责建立连接但是啥也没干,这个拦截器负责给服务器发消息并接收返回)

    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());
   
    return chain.proceed(originalRequest);//开启链式调用
  }

这里主要是拦截器的大概调用流程,首先添加自定义的拦截器(一般是日志打印拦截器或者再增加Header信息之类的),然后添加其他固定的拦截器,注意这里的拦截器顺序都是固定的,添加后用一个RealInterceptorChain包装并依次调用,执行顺序就是添加拦截器的顺序,这里每个的拦截器都是继承了Interceptor接口

public interface Interceptor {
  //拦截器子类 需复写的方法,基本每个拦截器的具体用法都在这个函数里面
  Response intercept(Chain chain) throws IOException;

  //拦截器调用链继承接口
  interface Chain {
    Request request();

    Response proceed(Request request) throws IOException;

    @Nullable Connection connection();

    Call call();

    int connectTimeoutMillis();

    Chain withConnectTimeout(int timeout, TimeUnit unit);

    int readTimeoutMillis();

    Chain withReadTimeout(int timeout, TimeUnit unit);

    int writeTimeoutMillis();

    Chain withWriteTimeout(int timeout, TimeUnit unit);
  }
}

再看看Chain子类RealInterceptorChain的关键方法proceed

  //带Response返回,方便做二次处理
  @Override public Response proceed(Request request) throws IOException {
    return proceed(request, streamAllocation, httpCodec, connection);
  
  }

  //这里仅贴出关键代码,该函数其他代码都是条件判断和返回处理
  public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    
   .........

    // 调用核心:直接index+1其他参数不变来调用下一个Interceptor
    RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
        connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);
   
    ...........

    return response;
  }

由此看出该方法主要是负责调用链的运转,当某个Interceptor在处理好大部分工作(注意这里说大部分是因为通过后面的Interceptor返回可以再做第二次处理,类似与Android View的触摸事件下发)后直接把原来的request丢过去调用chain.proceed(request),RealInterceptorChain类就会自动通过index+1来调用下一个Interceptor
。这里也可以看出虽然方法内一直next next next的 又有Chain这样的字眼让人误以为内部是链表结构存放Interceptor,其实是通过列表存放的
这里顺带科普一下列表和链表的大概优缺点(给自己看。。。。)
https://blog.csdn.net/st1441517927/article/details/99483738

总结

OkHttp通过拦截器设计模式非常的巧妙,一来是细化各个分功能解耦度高,层次分明,二来是方便定制(可以自定义拦截器), 再者采用类似Android 触摸事件分发的机制,使得每个Interceptor可以进行二次处理,非常关键,某些需要二次处理(或重点处理返回那一次)的就得益于这种机制,例如重定向拦截器和自定义的日志拦截器尤为明显

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容