开源库Android学习

OkHttp—流程全解析

2021-03-04  本文已影响0人  JackDaddy

想必一提到 Android 网络库 就会想到 OkHttp,今天就来分析一下 OkHttp 里面的整个整个流程

前言

注:本文 OkHttp 源码解析基于 v3.8.1 ,下文中涉及到展示 OkHttp 源码的地方,都采用在 AS 里打开源码并以截图的方式展现出来,这样更加直观。

一、简单使用

请求分为同步和异步两种:

//1.新建OKHttpClient客户端
OkHttpClient mClient = new OkHttpClient();
//2.新建一个Request对象
Request mRequest = new Request.Builder()
                .url(URL)
                .build();

//3.Response为OKHttp中的响应
//(1)同步请求
Response response = mClient.newCall(mRequest).execute();

//(2)异步请求
Response response = mClient.newCall(mRequest).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
    }
   @Override
   public void onResponse(Call call, Response response) throws IOException {
  }
});

二、流程分析

    从上面可以看到无论是 同步请求 还是 异步 请求,前两个步骤都是一致的,接下来一步一步来分析流程。
    第一步,先是 实例化 了一个 OKHttpClient 对象,这个 OKHttpClient 类就比较简单了,里面包含了很多对象,其实OKhttp的很多功能模块都包装进这个类,让这个类单独提供对外的 API,这种 外观模式的设计十分的优雅。而内部模块比较多,就使用了Builder 模式(建造者模式)。我们看下 OKHttpClient 的构造方法,代码如下:

OKHttpClient     通过上述代码我们可以看到,OKhttpClient 有两个构造方法,可以通过传入一个构建好的 Builder 来设置相关参数,也可以像我们的样例代码中那样采用默认的构造方法。默认的构造方法中会调用 OkHttpClient 内部类 Builder 的默认构造方法来设置默认模块参数。Builder 的默认构造方法如下:
OkHttpClient # Builder
第二步,构建一个 Request 对象,Request 和 第三步中的 Response 分别抽象成 请求响应
其中 Request 包括 HeadersRequestBody,而 RequestBodyabstract 的,他的子类有 FormBody (表单提交的)MultipartBody(文件上传),分别对应了两种不同的 MIME 类型,FormBody :"application/x-www-form-urlencoded"MultipartBody:"multipart/"+xxxResponse 包括 HeadersResponseBody,而 ResponseBodyabstract 的,所以他的子类也是有两个,RealResponseBodyCacheResponseBody,分别代表真实响应和缓存响应。
Reques & Respone

第三步,同步和异步都是先传入第二步中的 Request 对象来调用第一步中的 OkHttpClient 对象的 newCall(Request request)方法。我们看看这个 newCall() 方法里面做了什么,代码如下:

OkHttpClient#newCall client调用了 RealCall 的 newRealCall() 方法,而 RealCall 类实现了 Call 接口,并且是 Call 接口的唯一实现类,所以这个方法返回 Call 对象其实也就是返回 RealCall 对象了: RealCall 接着来看一下Call 这个接口: Call     可以说我们能用到的操操作基本上都定义在这个接口里面了,所以也可以说这个类是 OKHttp 的核心类了。我们可以通过 Call 对象来操作请求了。而 Call 接口内部提供了内部接口 Factory,用于将对象的创建延迟到该工厂类的子类中进行,从而实现动态的配置。这种方式是比较常见的 工厂方法模式
    前面第三步说到有两种请求方式:

而在第202-205行则是循环从执行队列中取出请求,在204行通过AsyncCall 执行 executeOn 方法执行请求。注意这里传入了 executorService() :

executorService 可以看到这里是一个线程池,这里有个很有趣的点:
  1. client.interceptors():用户自定义的 Interceptor。(第205行设置)
  2. RetryAndFollowUpInterceptor:负责失败重试以及重定向。
  3. BridgeInterceptor:负责把用户构造的请求转换为发送给服务器的请求,把服务器返回的响应转换为对用户友好的响应。
  4. CacheInterceptor:负责读取缓存以及更新缓存。
  5. ConnectInterceptor:负责与服务器建立连接。
  6. client.newworkInterceptors():用户自定义的网络层 Interceptor(在图 3-1 的 211 行设置)
  7. CallServerInterceptor:负责从服务器读取响应的数据。

位置决定功能,位置靠前的先执行(按以上顺序),最后一个则负责与服务器通讯,请求从 RetryAndFollowUpInterceptor (如果没有用户自定义的 Interceptor)开始层层传递到 CallServerInterceptor,每一层都对请求做相应的处理,处理的结果再从 CallServerInterceptor 层层返回给 RetryAndFollowUpInterceptor,最后请求的发起者获得了服务器返回的结果。注意这里第215行 的传入的index 值为 0 先来看下 Interceptor 这个接口的代码:

Interceptor 添加完 interceptor 后创建了一个 Interceptor.Chain,这个 Chain 是 Interceptor 接口的内部接口,被称为拦截器链,它的唯一实现类是 RealInterceptorChain。我们看一下 RealInterceptorChain 的构造方法,代码如下: RealInterceptorChain 前面说过传入的index为 0,因此,这里的 index 为 0,对应的是 interceptors 中当前执行的索引。创建完 RealInterceptorChain 紧接着就会去调用这个 chain 的 proceed 方法,代码如下: RealInterceptorChain#proceed 上述代码中,122 行是为了避免 List 索引越界。139 - 142 行主要做的工作是用当前的参数调用 RealInterceptorChain 的构造方法来再创建一个新的 RealInterceptorChain,其中传给下个 RealInterceptorChain 的 index 在当前基础上加 1 了,接着获取 interceptors 中当前 index 下的 Interceptor,然后调用这个 Interceptor 的 intercept(Chain chain) 方法,并将刚才构建的 RealInterceptorChain 作为参数传递。直到所有 interceptor 都处理完毕,然后将得到的 response 返回。

每个拦截器的方法都遵循这样的规则:


@Override public Response intercept(Chain chain) throws IOException {
    //1 Request阶段,该拦截器在Request阶段负责做的事情    
    Request request = chain.request();
 
    //2 调用RealInterceptorChain.proceed(),其实是在递归调用下一个拦截器的intercept()方法
    response = ((RealInterceptorChain) chain).proceed(request, transmitter, null);
 
    //3 Response阶段,完成了该拦截器在Response阶段负责做的事情,然后返回到上一层的拦截器。
    return response;     
  }

从上面的描述可知,Request 是按照 interpretors 的顺序正向处理,而 Response 是逆向处理的。它的实现采用责任链模式,这参考了OSI七层模型的原理。上面我们也提到过。CallServerInterceptor 相当于最底层的物理层, 请求从上到逐层包装下发,响应从下到上再逐层包装返回。


责任链
流程如下: 流程
上一篇下一篇

猜你喜欢

热点阅读