Connor学Android - OkHttp基本使用与源码解析

在这里插入图片描述

Learn && Live

虚度年华浮萍于世,勤学善思至死不渝

前言

Hey,欢迎阅读Connor学Android系列,这个系列记录了我的Android原理知识学习、复盘过程,欢迎各位大佬阅读斧正!原创不易,转载请注明出处:http://t.csdn.cn/EVHjI,话不多说我们马上开始!

1.使用

异步GET请求

(1)创建OkHttpClient对象

(2)通过Builder模式创建Request对象,参数必须有个url参数,可以通过Request.Builder设置更多的参数比如:header、method等

(3)通过request的对象去构造得到一个Call对象,Call对象有execute()和cancel()等方法。

(4)以异步的方式去执行请求,调用的是call.enqueue,将call加入调度队列,任务执行完成会在Callback中得到结果。

注意事项:

  • 异步调用的回调函数是在子线程,我们不能在子线程更新UI
  • onResponse回调有一个参数是response
    • 如果想获得返回的是字符串,可以通过response.body().string()
    • 如果获得返回的二进制字节数组,则调用response.body().bytes()
    • 如果想拿到返回的inputStream,则调response.body().byteStream(),之后通过IO的方式写文件

异步POST请求

与GET类似,只是需要传输实体

通过FormBody,添加多个String键值对,最后为Request添加post方法并传入formBody

2.基本对象介绍

OkHttpClient

创建 OkHttpClient 有两种方式:new 或 使用建造者模式为其设置一些参数,无论哪一种,实际上都是使用建造者模式完成的

open class OkHttpClient internal constructor(builder: Builder) 
	: Cloneable, Call.Factory, WebSocket.Factory {

  constructor() : this(Builder())

  class Builder constructor() {
  	//调度器
    internal var dispatcher: Dispatcher = Dispatcher()
    //连接池
    internal var connectionPool: ConnectionPool = ConnectionPool()
    //整体流程拦截器
    internal val interceptors: MutableList<Interceptor> = mutableListOf()
    //网络流程拦截器
    internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()
    //流程监听器
    internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()
    //连接失败时是否重连
    internal var retryOnConnectionFailure = true
    //服务器认证设置
    internal var authenticator: Authenticator = Authenticator.NONE
    //是否重定向
    internal var followRedirects = true
    //是否从HTTP重定向到HTTPS
    internal var followSslRedirects = true
    //cookie设置
    internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
    //缓存设置
    internal var cache: Cache? = null
    //DNS设置
    internal var dns: Dns = Dns.SYSTEM
    //代理设置
    internal var proxy: Proxy? = null
    //代理选择器设置
    internal var proxySelector: ProxySelector? = null
    //代理服务器认证设置
    internal var proxyAuthenticator: Authenticator = Authenticator.NONE
    //socket配置
    internal var socketFactory: SocketFactory = SocketFactory.getDefault()
    //https socket配置
    internal var sslSocketFactoryOrNull: SSLSocketFactory? = null
    internal var x509TrustManagerOrNull: X509TrustManager? = null
    internal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECS
    //协议
    internal var protocols: List<Protocol> = DEFAULT_PROTOCOLS
    //域名校验
    internal var hostnameVerifier: HostnameVerifier = OkHostnameVerifier
    internal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULT
    internal var certificateChainCleaner: CertificateChainCleaner? = null
    //请求超时
    internal var callTimeout = 0
    //连接超时
    internal var connectTimeout = 10_000
    //读取超时
    internal var readTimeout = 10_000
    //写入超时
    internal var writeTimeout = 10_000
    internal var pingInterval = 0
    internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZE
    internal var routeDatabase: RouteDatabase? = null
  }
}

Request

同样是请求参数的配置类,也同样采用了建造者模式,但相比于OkHttpClientRequest就十分简单了,只有四个参数,分别是请求URL、请求方法、请求头、请求体

class Request internal constructor(
  @get:JvmName("url") val url: HttpUrl,
  @get:JvmName("method") val method: String,
  @get:JvmName("headers") val headers: Headers,
  @get:JvmName("body") val body: RequestBody?,
  internal val tags: Map<Class<*>, Any>
) {

  open class Builder {
  	//请求的URL
    internal var url: HttpUrl? = null
    //请求方法,如:GET、POST..
    internal var method: String
    //请求头
    internal var headers: Headers.Builder
    //请求体
    internal var body: RequestBody? = null
  }
}

Call

请求调用接口,针对请求提供了一系列的操作方法,常见的有

  • request():返回 Request 对象
  • execute():同步请求,立即执行,请求失败抛出 IOException、执行过一次后再次执行抛出 IllegalStateException
  • enqueue():异步请求,将请求安排在将来某个时间点执行,若执行过一次后再次执行抛出 IllegalStateException
  • cancel():取消请求,注意已经完成的请求不能被取消
  • 利用工厂模式来让 OkHttpClient 、Request 对象来创建 newCall 对象
interface Call : Cloneable {
  /** 返回发起此调用的原始请求 */
  fun request(): Request

  /**
   * 同步请求,立即执行。
   * 
   * 抛出两种异常:
   * 1. 请求失败抛出IOException;
   * 2. 如果在执行过一回的前提下再次执行抛出IllegalStateException;*/
  @Throws(IOException::class)
  fun execute(): Response

  /**
   * 异步请求,将请求安排在将来的某个时间点执行。
   * 如果在执行过一回的前提下再次执行抛出IllegalStateException */
  fun enqueue(responseCallback: Callback)

  /** 取消请求。已经完成的请求不能被取消 */
  fun cancel()

  /** 是否已被执行  */
  fun isExecuted(): Boolean

  /** 是否被取消   */
  fun isCanceled(): Boolean

  /** 一个完整Call请求流程的超时时间配置,默认选自[OkHttpClient.Builder.callTimeout] */
  fun timeout(): Timeout

  /** 克隆这个call,创建一个新的相同的Call */
  public override fun clone(): Call

  /** 利用工厂模式来让 OkHttpClient 来创建 Call对象 */
  fun interface Factory {
    fun newCall(request: Request): Call
  }
}

RealCall

(1)在使用时,通过 OkHttpClient 的 newCall() 方法创建一个 Call 对象,通过源码知道,newCall() 方法返回的是一个 RealCall 对象

(2)RealCall 是 Call 接口的实现类,内部有三个参数:OkHttpClient、Request、是否使用 WebSocket(默认为 false)

(3)RealCall 实现了上述 Call 接口的方法,因此可以调用 execute() 和 enqueue() 方法完成同步或异步请求方法

override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

AsyncCall

(1)是 RealCall 的一个内部类,它继承自 NamedRunnable,NamedRunnable 实现了 Runnable 接口,它的作用有两个:

  • 采用模板方法的设计模式,让子类将具体的操作放在 execute() 方法中

  • 给线程指定一个名字,比如传入模块名称,方便监控线程的活动状态

(2)AsyncCall 实现了 execute() 方法,用于异步请求下的调用,后续的流程分析会做详细介绍

Dispatcher

(1)调度器,用于调度 Call 对象

(2)内部包含

  • 最大任务请求数限制,不可大于64

  • ThreadPoolExecutor 作为默认线程池,也可以通过构造方法执行其他线程池

  • ArrayDeque 类型的 readyAsyncCalls 已准备好的异步请求队列

  • ArrayDeque 类型的 runningAsyncCalls 正在运行的异步请求队列,包含取消但是还未 finish 的 AsyncCall

  • ArrayDeque 类型的 runningSyncCalls 正在运行的同步请求队列,包含取消但是还未 finish 的 RealCall

class Dispatcher constructor() {
  @get:Synchronized
  @get:JvmName("executorService") val executorService: ExecutorService
    get() {
      if (executorServiceOrNull == null) {
        //创建一个缓存线程池,来处理请求调用
        executorServiceOrNull = ThreadPoolExecutor(0, Int.MAX_VALUE, 60, TimeUnit.SECONDS,
            SynchronousQueue(), threadFactory("$okHttpName Dispatcher", false))
      }
      return executorServiceOrNull!!
    }

  /** 已准备好的异步请求队列 */
  @get:Synchronized
  private val readyAsyncCalls = ArrayDeque<AsyncCall>()

  /** 正在运行的异步请求队列, 包含取消但是还未finish的AsyncCall */
  private val runningAsyncCalls = ArrayDeque<AsyncCall>()

  /** 正在运行的同步请求队列, 包含取消但是还未finish的RealCall */
  private val runningSyncCalls = ArrayDeque<RealCall>()

···省略代码···
}

总结

对象作用
Call请求调用接口,表示这个请求已经准备好可以执行,也可以被取消,只能执行一次
RealCallCall 接口的具体实现类,是应用与网络层之间的连接桥,包含 OkHttpClient 和 Request 信息
AsyncCall异步请求调用,其实就是个 Runnable,会被放到线程池中进行处理
Dispatcher调度器,用来调度 Call 对象,同时包含线程池与异步请求队列,用来存放与执行 AsyncCall 对象
Request请求类,包含 url、method、headers、body
Response网络层返回的响应数据
Callback响应回调函数接口,包含 onFailure 、onResponse 两个方法
3.异步请求流程分析

(1)异步请求首先会调用 RealCall 的 enqueue() 方法,这个方法内会做两件事

  • 检查是否重复调用了 enqueue() 方法
  • 调用 Dispatcher 的 enqueue() 方法,并将 AsyncCall 传进去

(2)Dispatcher 的 enqueue() 方法内会将传入的 AsyncCall 加入 Dispatcher 的 ready 队列中,并调用 promoteAndExecutor() 方法

(3)promoteAndExecutor() 方法内会遍历 ready 队列,取出每个 AsyncCall,并对当前的运行状态做双重约束

  • running 队列中的个数不可以超出最大请求数,若不满足则直接退出遍历循环,直至 running 队列有空位
  • AsyncCall 中的主机数不可以超出同一主机的最大任务数,若不满足则遍历下一个 AsyncCall

若满足则将当前的 AsyncCall 添加到 running 队列中,并调用 AsyncCall 的 executeOn 方法

(4)executeOn 方法中主要做三件事

  • 将当前遍历到的 AsyncCall 添加到线程池 executorService 中,调用 execute() 方法执行异步任务
  • 通过拦截器链来得到网络响应
  • 无论相应成功还是失败,都会调用 Dispatcher 中的 finished 方法

(5)finished() 方法内主要做两件事

  • 将已执行完的 AsyncCall 退出 running 队列
  • 继续调用 promoteAndExecute() 方法遍历 ready 队列中的下一个 AsyncCall,形成完美闭环

拦截器链

(1)AsyncCall 的 executeOn() 方法中会通过拦截器链来得到网络相应,这里调用的是 getResponseWithInterceptorChain() 方法

(2)这个方法主要做了两件事:

  • 创建拦截器集合,并将所有的拦截器
  • 创建职责链,并调用 proceed() 方法启动
    • 职责链采用的是职责链模式,使得每一个拦截器都有机会处理请求
      • 网络请求经过拦截器链的处理发送
      • 响应也会经过拦截器链的处理返回给应用层
    • proceed() 内会调用 RealInterceptorChain 的 copy() 方法,其内部会创建一个 RealInterceptorChain ,并循环处理每个拦截器
      • 首先获取当前要执行的拦截器
      • 运行当前拦截器,等当前拦截器处理完成后,会接着执行下一个拦截器的 proceed

(3)各个拦截器的作用

  • interceptor:应用拦截器,通过 Client 设置
  • RetryAndFollowUpInterceptor:重试拦截器,负责网络请求中的重试和重定向。比如网络请求过程中出现异常时重试请求
  • BridgeInterceptor:桥接拦截器,用于桥接应用层和网络层的数据。请求时将应用层的数据类型转换为网络层的数据类型,响应时则相反
  • CacheInterceptor:缓存拦截器,负责读取和更新缓存。可以配置自定义的缓存拦截器
  • ConnectInterceptor:网络连接拦截器,其内部会获取一个连接
  • networkInterceptor:网络拦截器,通过 Client 设置
  • CallServerInterceptor:请求服务拦截器。拦截链中位于末尾的拦截器,用于向服务端发送数据并获取响应
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ConnorYan

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值