OkHttp探索

前言

OkHttp 是移动支付Square公司推出的一款网络请求处理框架。是Android开发使用最多最火热的一款网络请求框架,下面就OkHttp使用和源码进行探索。

OkHttp简单使用

1.添加依赖

implementation("com.squareup.okhttp3:okhttp:4.9.0")

2.初始化OkHttpClient

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
                .get()
                .url("你的URL")
                .build();

也可以

OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder();
okHttpClient.readTimeout(mReadTimeOut, TimeUnit.MILLISECONDS);
okHttpClient.connectTimeout(mConnectTimeOut,TimeUnit.MILLISECONDS);
okHttpClient.writeTimeout(mWriteTimeOut, TimeUnit.MILLISECONDS);
okHttpClient.build();

3.将Request封装为Call

Call call = client.okHttpClient(request);

4.发送一个同步请求

Response response = okHttpClient.newCall(request).execute();
String result = response.body().string();

5.发送一个异步请求

    okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String json= response.body().string();       
            }
        });

OkHttpClient.Builder

OkHttpClient采用了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
    internal var followSslRedirects = true
    internal var cookieJar: CookieJar = CookieJar.NO_COOKIES
    internal var cache: Cache? = null
    internal var dns: Dns = Dns.SYSTEM
    internal var proxy: Proxy? = null
    internal var proxySelector: ProxySelector? = null
    internal var proxyAuthenticator: Authenticator = Authenticator.NONE
    internal var socketFactory: SocketFactory = SocketFactory.getDefault()
    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

以上代码可以看出有很多属性我们可以供我们配置,比如读写超时、失败重连等扩展性很强。

okHttpClient.newCall

  /** Prepares the [request] to be executed at some point in the future. */
  override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

返回了RealCall对象,它是Call的实现类。看下RealCall

  override fun execute(): Response {
    check(executed.compareAndSet(false, true)) { "Already Executed" }

    timeout.enter()
    callStart()
    try {
      client.dispatcher.executed(this)
      return getResponseWithInterceptorChain()
    } finally {
      client.dispatcher.finished(this)
    }
  }

  override fun enqueue(responseCallback: Callback) {
    check(executed.compareAndSet(false, true)) { "Already Executed" }

    callStart()
    client.dispatcher.enqueue(AsyncCall(responseCallback))
  }

上面的核心代码getResponseWithInterceptorChain()方法是真正进行网络请求的地方。源码如下

 @Throws(IOException::class)
  internal fun getResponseWithInterceptorChain(): Response {
    // Build a full stack of interceptors.
    val interceptors = mutableListOf<Interceptor>()
    interceptors += client.interceptors
    interceptors += RetryAndFollowUpInterceptor(client)
    interceptors += BridgeInterceptor(client.cookieJar)
    interceptors += CacheInterceptor(client.cache)
    interceptors += ConnectInterceptor
    if (!forWebSocket) {
      interceptors += client.networkInterceptors
    }
    interceptors += CallServerInterceptor(forWebSocket)

    val chain = RealInterceptorChain(
        call = this,
        interceptors = interceptors,
        index = 0,
        exchange = null,
        request = originalRequest,
        connectTimeoutMillis = client.connectTimeoutMillis,
        readTimeoutMillis = client.readTimeoutMillis,
        writeTimeoutMillis = client.writeTimeoutMillis
    )

    var calledNoMoreExchanges = false
    try {
      val response = chain.proceed(originalRequest)
      if (isCanceled()) {
        response.closeQuietly()
        throw IOException("Canceled")
      }
      return response
    } catch (e: IOException) {
      calledNoMoreExchanges = true
      throw noMoreExchanges(e) as Throwable
    } finally {
      if (!calledNoMoreExchanges) {
        noMoreExchanges(null)
      }
    }
  }

请求会被交给责任链中的一个个拦截器。默认如下五个拦截器
1.RetryAndFollowUpInterceptor(重试和重定向拦截器)
第一个接触到请求,最后接触到响应(U型调用);负责判断是否需要重新发起整个请求
2.BridgeInterceptor(桥接拦截器)
补全请求,并对响应进行额外处理
3.CacheInterceptor(缓存拦截器)
请求前查询缓存,获得响应并判断是否需要缓存
4.ConnectInterceptor(链接拦截器)
与服务器完成TCP连接
5.CallServerInterceptor(请求服务拦截器)
与服务器通信;封装请求数据与解析响应数据(如:HTTP报文)

OkHttpClient.Builder的第一行代码

internal var dispatcher: Dispatcher = Dispatcher()

和同步、异步请求方法都调用了client.dispatcher,这里的dispatcher就是下面要说的Dispatcher了。

什么是Dispatcher在Okhttp中有什么作用?

Dispatcher

Dispatcher是什么?

Dispatcher的作用是维护众多请求的状态,并维护一个线程池,用于执行请求。发送的同步/异步请求都会在dispatcher中管理其状态。


  /**
   * The maximum number of requests to execute concurrently. Above this requests queue in memory,
   * waiting for the running calls to complete.
   *
   * If more than [maxRequests] requests are in flight when this is invoked, those requests will
   * remain in flight.
   */
  @get:Synchronized var maxRequests = 64
    set(maxRequests) {
      require(maxRequests >= 1) { "max < 1: $maxRequests" }
      synchronized(this) {
        field = maxRequests
      }
      promoteAndExecute()
    }
    
/**
   * The maximum number of requests for each host to execute concurrently. This limits requests by
   * the URL's host name. Note that concurrent requests to a single IP address may still exceed this
   * limit: multiple hostnames may share an IP address or be routed through the same HTTP proxy.
   *
   * If more than [maxRequestsPerHost] requests are in flight when this is invoked, those requests
   * will remain in flight.
   *
   * WebSocket connections to hosts **do not** count against this limit.
   */
  @get:Synchronized var maxRequestsPerHost = 5
    set(maxRequestsPerHost) {
      require(maxRequestsPerHost >= 1) { "max < 1: $maxRequestsPerHost" }
      synchronized(this) {
        field = maxRequestsPerHost
      }
      promoteAndExecute()
    }

 /** Ready async calls in the order they'll be run. */
  private val readyAsyncCalls = ArrayDeque<AsyncCall>()

  /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
  private val runningAsyncCalls = ArrayDeque<AsyncCall>()

  /** Running synchronous calls. Includes canceled calls that haven't finished yet. */
  private val runningSyncCalls = ArrayDeque<RealCall>()

  constructor(executorService: ExecutorService) : this() {
    this.executorServiceOrNull = executorService
  }
1 ExecutorService线程池,用于执行请求。
2 readyAsyncCalls 异步请求的就绪队列,用于保存等待执行的请求。
3 runningAsyncCalls 异步请求的执行队列,包括已经取消(cancel)但是还没被finish掉的请求。
4 runningSyncCalls 同步请求的执行队列,包括已经取消(cancel)但是还没被finish掉的请求。
  /**
   * Promotes eligible calls from [readyAsyncCalls] to [runningAsyncCalls] and runs them on the
   * executor service. Must not be called with synchronization because executing calls can call
   * into user code.
   *
   * @return true if the dispatcher is currently running calls.
   */
  private fun promoteAndExecute(): Boolean {
    this.assertThreadDoesntHoldLock()

    val executableCalls = mutableListOf<AsyncCall>()
    val isRunning: Boolean
    synchronized(this) {
      val i = readyAsyncCalls.iterator()
      while (i.hasNext()) {
        val asyncCall = i.next()

        if (runningAsyncCalls.size >= this.maxRequests) break // Max capacity.
        if (asyncCall.callsPerHost.get() >= this.maxRequestsPerHost) continue // Host max capacity.

        i.remove()
        asyncCall.callsPerHost.incrementAndGet()
        executableCalls.add(asyncCall)
        runningAsyncCalls.add(asyncCall)
      }
      isRunning = runningCallsCount() > 0
    }

    for (i in 0 until executableCalls.size) {
      val asyncCall = executableCalls[i]
      asyncCall.executeOn(executorService)
    }

    return isRunning
  }

1.首先判断最大请求个数是否超过了maxRequests=64个和相同host是否超过了maxRequestsPerHost=5个。
2.如果都没到最大限制,则把当前的AsyncCall从readyAsyncCalls集合中移除掉,同时对RealCall的host个数+1操作,同时加到runningAsyncCalls和executableCalls集合中。
3.最后遍历executableCalls集合,执行AsyncCall的executeOn方法,这里要注意executorService方法是返回了一个线程池。所以最后执行任务的是在asyncCall的executeOn方法。

OkHttp的优点

网络优化方面:
(1)内置连接池,支持连接复用;
(2)支持gzip压缩响应体;
(3)通过缓存避免重复的请求;
(4)支持http2,对一台机器的所有请求共享同一个socket。

功能方面:
功能全面,满足了网络请求的大部分需求

扩展性方面:
责任链模式使得很容易添加一个自定义拦截器对请求和返回结果进行处理

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值