hi,你好!欢迎访问本站!登录
本站由网站地图腾讯云宝塔系统阿里云强势驱动
当前位置:首页 - 教程 - 杂谈 - 正文 君子好学,自强不息!

Okhttp 要求流程梳理

2019-11-18杂谈搜奇网35°c
A+ A-

近来在看 Okhttp 的源码。不得不说源码设想的很奇妙,从中能学到许多。实在网上关于 Okhttp 的文章已许多了,本身也看了许多。然则俗话说得好,好记性不如烂笔头,当你着手的时刻,你会发明你在看的时刻没有注意到的许多细节。

本次要剖析的 Okhttp 版本是 3.8.1,在 gradle 中援用以下:

implementation 'com.squareup.okhttp3:okhttp:3.8.1'
implementation 'com.squareup.okio:okio:1.7.0'

之所以挑选剖析3.8.1,是由于最新版是采纳 Kotlin 写的,由于本人 Kotlin 气力不允许,所以只能剖析 Java 版本。

运用示例

1、提议一个异步 GET 要求,代码详细以下:

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
        .url(url)
        .get()//默许就是GET要求,能够不写
        .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());
    }
});

 2、提议一个同步 GET 要求,代码详细以下:

String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
        .url(url)
        .build();
final Call call = okHttpClient.newCall(request);
new Thread(new Runnable() {
    @Override
    public void run() {
        try {
            Response response = call.execute();
            Log.d(TAG, "run: " + response.body().string());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}).start();

 能够看到两个要求基础迥然不同,总结下历程以下:

  • 先竖立 OkHttpClient 实例;

  • 组织 Request 实例,传入 url 等相干参数;

  • 经由过程前两步中的实例对象构建 Call 对象;

  • 异步要求经由过程 Call#enqueue(Callback) 要领来提交异步要求,同步要求经由过程 Call#execute() 直接猎取 Reponse ;

经由过程示例,人人简朴相识 Okhttp 中的一些对象,下面最先梳理全部要求逻辑。先从 OkHttpClient 最先。

OkHttpClient

当我们提议要求的时刻,须要先组织 okHttpClient 对象,代码详细以下:

  public OkHttpClient() {
    this(new Builder());
  }

能够发明是运用了 builder 制作者形式;来看看内里的内容

public Builder() {
      dispatcher = new Dispatcher();  // 调理器
      protocols = DEFAULT_PROTOCOLS;  // 协定
      connectionSpecs = DEFAULT_CONNECTION_SPECS; //传输层版本和衔接协定
      eventListenerFactory = EventListener.factory(EventListener.NONE);
      proxySelector = ProxySelector.getDefault();
      cookieJar = CookieJar.NO_COOKIES;    //cookie
      socketFactory = SocketFactory.getDefault();
      hostnameVerifier = OkHostnameVerifier.INSTANCE;
      certificatePinner = CertificatePinner.DEFAULT;   //证书链
      proxyAuthenticator = Authenticator.NONE;    //代办身份验证
      authenticator = Authenticator.NONE;    //当地身份验证
      connectionPool = new ConnectionPool();    //链接池 复用衔接
      dns = Dns.SYSTEM;   //域名
      followSslRedirects = true;
      followRedirects = true;   //当地重定向
      retryOnConnectionFailure = true;
      connectTimeout = 10_000;
      readTimeout = 10_000;   //读取超时
      writeTimeout = 10_000;  //写入超时
      pingInterval = 0;
}
OkHttpClient 内部已完成了 OkHttpClient(Builder builder),假如我们不须要设置 client,okhttp 已将帮我们默许完成了设置。总结起来重要有以下几点:
  • 内里包含了许多对象,实在 OKhttp 的许多功用模块都包装进这个类,让这个类零丁供应对外的 API,这类表面形式的设想异常的文雅,叫做表面形式。
  • 而内部模块比较多,就运用了 Builder 形式(制作器形式),一般用于参数比较多状况。
  • 它的要领只需一个:newCall 返回一个 Call 对象(一个预备好了的能够实行和作废的要求)。

Request

接下来,我们看 Request 要求类,重要包含下面几个属性: url,要求要领名,要求头部,要求体,从属性就能够推断出 Request 重要作用。
  Request(Builder builder) {
    this.url = builder.url;
    this.method = builder.method;
    this.headers = builder.headers.build();
    this.body = builder.body;
    this.tag = builder.tag != null ? builder.tag : this;
  }

 Call

HTTP要求使命封装。能够说我们能用到的支配基础上都定义在这个接口内里了,所以也能够说这个类是 Okhttp 类的中心类了。我们能够经由过程 Call 对象来操纵要求了。而 Call 接口内部供应了 Factory 工场要领形式 (将对象的竖立延晚到工场类的子类去举行,从而完成动态设置),下面是 Call 接口的详细内容:

public interface Call extends Cloneable {
  /** Returns the original request that initiated this call. */
  Request request();

  /**
   * Invokes the request immediately, and blocks until the response can be processed or is in
   * error.
   *
   * <p>To avoid leaking resources callers should close the {@link Response} which in turn will
   * close the underlying {@link ResponseBody}.
   *
   * <pre>@{code
   *
   *   // ensure the response (and underlying response body) is closed
   *   try (Response response = client.newCall(request).execute()) {
   *     ...
   *   }
   *
   * }</pre>
   *
   * <p>The caller may read the response body with the response's {@link Response#body} method. To
   * avoid leaking resources callers must {@linkplain ResponseBody close the response body} or the
   * Response.
   *
   * <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does
   * not necessarily indicate application-layer success: {@code response} may still indicate an
   * unhappy HTTP response code like 404 or 500.
   *
   * @throws IOException if the request could not be executed due to cancellation, a connectivity
   * problem or timeout. Because networks can fail during an exchange, it is possible that the
   * remote server accepted the request before the failure.
   * @throws IllegalStateException when the call has already been executed.
   */
  Response execute() throws IOException;

  /**
   * Schedules the request to be executed at some point in the future.
   *
   * <p>The {@link OkHttpClient#dispatcher dispatcher} defines when the request will run: usually
   * immediately unless there are several other requests currently being executed.
   *
   * <p>This client will later call back {@code responseCallback} with either an HTTP response or a
   * failure exception.
   *
   * @throws IllegalStateException when the call has already been executed.
   */
  void enqueue(Callback responseCallback);

  /** Cancels the request, if possible. Requests that are already complete cannot be canceled. */
  void cancel();

  /**
   * Returns true if this call has been either {@linkplain #execute() executed} or {@linkplain
   * #enqueue(Callback) enqueued}. It is an error to execute a call more than once.
   */
  boolean isExecuted();

  boolean isCanceled();

  /**
   * Create a new, identical call to this one which can be enqueued or executed even if this call
   * has already been.
   */
  Call clone();

  interface Factory {
    Call newCall(Request request);
  }
}

 RealCall

 RealCall 继承自 Call,是真正提议要求的的实体类。RealCall 重要要领:

  • 同步要求 :client.newCall(request).execute();

  • 异步要求: client.newCall(request).enqueue();

下面我们来看看内里详细的内容:

 RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
    final EventListener.Factory eventListenerFactory = client.eventListenerFactory();

    this.client = client;
    this.originalRequest = originalRequest;
    this.forWebSocket = forWebSocket;
    this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);

    // TODO(jwilson): this is unsafe publication and not threadsafe.
    this.eventListener = eventListenerFactory.create(this);
  }

能够发明,其内部持有了 client,原始要求,以及要求事宜回调 Listener 等。我们看下要求的回调 Listener 的详细内容:

  public void fetchStart(Call call) {
  }

  public void dnsStart(Call call, String domainName) {
  }

  public void dnsEnd(Call call, String domainName, List<InetAddress> inetAddressList,
      Throwable throwable) {
  }

  public void connectStart(Call call, InetAddress address, int port) {
  }

  public void secureConnectStart(Call call) {
  }

  public void secureConnectEnd(Call call, Handshake handshake,
      Throwable throwable) {
  }

  public void connectEnd(Call call,  InetAddress address, int port, String protocol,
      Throwable throwable) {
  }

  public void requestHeadersStart(Call call) {
  }

  public void requestHeadersEnd(Call call, Throwable throwable) {
  }

  public void requestBodyStart(Call call) {
  }

  public void requestBodyEnd(Call call, Throwable throwable) {
  }

  public void responseHeadersStart(Call call) {
  }

  public void responseHeadersEnd(Call call, Throwable throwable) {
  }

  public void responseBodyStart(Call call) {
  }

  public void responseBodyEnd(Call call, Throwable throwable) {
  }

  public void fetchEnd(Call call, Throwable throwable) {
  }

能够看到 OkHttp 的回调做得异常仔细,有林林总总的回调,不论你想不想用,都帮你斟酌到了呢。如许我们能够监听详细的回调,然后做一些操纵。

接下去就要最先讲异步要求的详细步骤呢。先从异步要求讲起,这也是我们最经常使用的。

// RealCall  
@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }

能够看到上述代码做了几件事:

  • synchronized (this) 确保每一个call只能被实行一次不能反复实行,假如想要完全相同的 call,能够挪用以下要领:举行克隆
@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override public RealCall clone() {
    return RealCall.newRealCall(client, originalRequest, forWebSocket);
}
  • 运用 dispatcher 调理器,来举行现实的实行 client.dispatcher().enqueue(new AsyncCall(responseCallback)),在上面的 OkHttpClient.Builder 能够看出已初始化了 Dispatcher。

心细的读者能够发明一个问题了,那就是这里 enqueue 明显是一个封装了 responseCallback 的 AsyncCall ,怎样就会变成到场行列实行要求了呢?这个下面我会举行诠释。

Dispatcher 

Dispatcher 是 Okhttp 的调理器,用来治理掌握要求的行列。内部经由过程线程池来确保行列的有序运转。先看下 enqueue 要领的详细内容:

 synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

能够看到内部存在两个行列,一个是正在运转的行列 runningAsyncCalls,另一个是 readyAsyncCalls 行列。假如当前运转数小于最大运转数,而且当前要求的host小于最大要求个数,那末就会直接到场运转行列,并运转。假如超了,就会到场预备行列。

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

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

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

现实上另有一个同步行列,没有给同步行列做限定,只需一到场就最先实行要求。

当要求行列完成要求后须要举行移除,看下 finished 的代码逻辑:

  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
      if (promoteCalls) promoteCalls();
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }

    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

能够看到,这是运用了泛型,不必体贴详细传入的行列是哪个,直接就能够移除。promoteCalls 为 true 代表是异步要求行列,还得从 readyAsyncCalls 行列内里掏出一个行列添加到 runningAsyncCalls 行列内里去实行要求。

private void promoteCalls() {
    if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
    if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

    for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
      AsyncCall call = i.next();

      if (runningCallsForHost(call) < maxRequestsPerHost) {
        i.remove();
        runningAsyncCalls.add(call);
        executorService().execute(call);
      }

      if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
    }
  }

经由过程上述代码,关于调理器的功用作用就基础理清了。

AsyncCall

 AsyncCall 是 RealCall 内里的内部类,继承自 NamedRunnable,是自定义的Runnable,能够为线程设置 name。内部代码详细以下:

public abstract class NamedRunnable implements Runnable {
  protected final String name;

  public NamedRunnable(String format, Object... args) {
    this.name = Util.format(format, args);
  }

  @Override public final void run() {
    String oldName = Thread.currentThread().getName();
    Thread.currentThread().setName(name);
    try {
      execute();
    } finally {
      Thread.currentThread().setName(oldName);
    }
  }

  protected abstract void execute();
}

能够发明,在 run 要领内部挪用了execute 要领,这个要领就是真正的提议要求的逻辑。下面我们看下 AsyncCall 中的该要领得详细内容:

  @Override protected void execute() {
      boolean signalledCallback = false;
      try {
        Response response = getResponseWithInterceptorChain();
        if (retryAndFollowUpInterceptor.isCanceled()) {
          signalledCallback = true;
          responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
        } else {
          signalledCallback = true;
          responseCallback.onResponse(RealCall.this, response);
        }
      } catch (IOException e) {
        if (signalledCallback) {
          // Do not signal the callback twice!
          Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
        } else {
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

猎取相应数据终究是是经由过程 getResponseWithInterceptorChain() 来猎取的。然后经由过程回调将 Response 返回给用户。

值得注意的 finally 实行了client.dispatcher().finished(this) 经由过程调理器移除行列。移除得逻辑在前面也已讲过了。

下面看下 getResponseWithInterceptorChain 要领内部的详细逻辑:

//Realcall 中心代码 最先真正的实行收集要求
  Response getResponseWithInterceptorChain() throws IOException {
    // Build a full stack of interceptors.
    // 义务链
    List<Interceptor> interceptors = new ArrayList<>();
    // 在设置okhttpClient 时设置的intercept 由用户本身设置
    interceptors.addAll(client.interceptors());
    // 担任处置惩罚失利后的重试与重定向
    interceptors.add(retryAndFollowUpInterceptor);
    // 担任把用户组织的要求转换为发送到效劳器的要求 、把效劳器返回的相应转换为用户友爱的相应 处置惩罚 设置要求优等信息
    // 从运用程序代码到收集代码的桥梁。起首,它依据用户要求构建收集要求。然后它继承呼唤收集。末了,它依据收集相应构建用户相应。
    interceptors.add(new BridgeInterceptor(client.cookieJar()));
    // 处置惩罚 缓存设置 依据前提(存在相应缓存并被设置为稳定的或许相应在有效期内)返回缓存相应
    // 设置要求头(If-None-Match、If-Modified-Since等) 效劳器能够返回304(未修改)
    // 可设置用户本身设置的缓存拦截器
    interceptors.add(new CacheInterceptor(client.internalCache()));
    // 衔接效劳器 担任和效劳器竖立衔接 这里才是真正的要求收集
    interceptors.add(new ConnectInterceptor(client));
    if (!forWebSocket) {
      // 设置okhttpClient 时设置的networkInterceptors
      // 返回视察单个收集要乞降相应的不可变拦截器列表。
      interceptors.addAll(client.networkInterceptors());
    }
    // 实行流操纵(写出要求体、取得相应数据) 担任向效劳器发送要求数据、从效劳器读取相应数据
    // 举行http要求报文的封装与要求报文的剖析
    interceptors.add(new CallServerInterceptor(forWebSocket));

    // 竖立义务链
    Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
        originalRequest, this, eventListener, client.connectTimeoutMillis(),
        client.readTimeoutMillis(), client.writeTimeoutMillis());

    //TODO 实行义务链
    return chain.proceed(originalRequest);
  }
从上述代码中,能够看出都完成了 Interceptor 接口,这是 Okhttp 最中心的部份,采纳义务链的形式来使每一个功用离开,每一个 Interceptor 自行完成本身的使命,而且将不属于本身的使命交给下一个,简化了各自的义务和逻辑。

RealInterceptorChain

那义务链是怎样完成的呢?下面详细剖析下相干逻辑:
  public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
      HttpCodec httpCodec, RealConnection connection, int index, Request request) {
    this.interceptors = interceptors;
    this.connection = connection;
    this.streamAllocation = streamAllocation;
    this.httpCodec = httpCodec;
    this.index = index;
    this.request = request;
  }
// 义务链处置惩罚
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
      RealConnection connection) throws IOException {
    if (index >= interceptors.size()) throw new AssertionError();

    calls++;

    // If we already have a stream, confirm that the incoming request will use it.
    if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must retain the same host and port");
    }

    // If we already have a stream, confirm that this is the only call to chain.proceed().
    if (this.httpCodec != null && calls > 1) {
      throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
          + " must call proceed() exactly once");
    }

    // Call the next interceptor in the chain.
    RealInterceptorChain next = new RealInterceptorChain(
        interceptors, streamAllocation, httpCodec, connection, index + 1, request);
    Interceptor interceptor = interceptors.get(index);
    Response response = interceptor.intercept(next);

    // Confirm that the next interceptor made its required call to chain.proceed().
    if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
      throw new IllegalStateException("network interceptor " + interceptor
          + " must call proceed() exactly once");
    }

    // Confirm that the intercepted response isn't null.
    if (response == null) {
      throw new NullPointerException("interceptor " + interceptor + " returned null");
    }

    return response;
  }

 起首是看组织函数,内部持有了当前义务链的一切拦截器list,还包含 RealConnection,index (当前正在处置惩罚拦截器索引)等。

接下去看 proceed 要领里的逻辑,返来起来就是以下:

  1. 起首是经由过程 index 和 calls 来做了一些平安推断,防止反复处置惩罚,。

  2. 将索引号 index +1,新竖立一个 chain。

  3. 依据现在的 index 猎取拦截器,然后将新的 chain 传入到猎取拦截器中。

  4. 拦截器做完本身的操纵后,会挪用新竖立的 chain 的 proceed 要领,交由下一个拦截器来处置惩罚。

  5. 当数据返回后,从后往前,拦截器会顺次对数据做一些处置惩罚,终究用户取得要求的数据。

经由过程上述来去轮回,终究一切的拦截器都邑走两遍,一次是对要求体做操纵,一次是对返回体做操纵,终究用户取得处置惩罚后的数据。

下面来看一个详细的拦截器 。

 CacheInterceptor

CacheInterceptor 代码比较长,我们一步一步的来举行剖析。

起首我们先剖析上部份代码当没有收集的状况下是怎样处置惩罚猎取缓存的。

  @Override public Response intercept(Chain chain) throws IOException
  {
// 猎取request对应缓存的Response 假如用户没有设置缓存拦截器 cacheCandidate == null
    Response cacheCandidate = cache != null
        ? cache.get(chain.request())
        : null;

    // 实行相应缓存战略
    long now = System.currentTimeMillis();
    CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
    // 假如networkRequest == null 则申明不运用收集要求
    Request networkRequest = strategy.networkRequest;
    // 猎取缓存中(CacheStrategy)的Response
    Response cacheResponse = strategy.cacheResponse;

    if (cache != null) {
      cache.trackResponse(strategy);
    }
    // 缓存无效 封闭资本
    if (cacheCandidate != null && cacheResponse == null) {
      closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
    }

    // If we're forbidden from using the network and the cache is insufficient, fail.
    // networkRequest == null 不实用网路要求 且没有缓存 cacheResponse == null  返回失利
    if (networkRequest == null && cacheResponse == null) {
      return new Response.Builder()
          .request(chain.request())
          .protocol(Protocol.HTTP_1_1)
          .code(504)
          .message("Unsatisfiable Request (only-if-cached)")
          .body(Util.EMPTY_RESPONSE)
          .sentRequestAtMillis(-1L)
          .receivedResponseAtMillis(System.currentTimeMillis())
          .build();
    }

    // 不运用收集要求 且存在缓存 直接返回相应
    // If we don't need the network, we're done.
    if (networkRequest == null) {
      return cacheResponse.newBuilder()
          .cacheResponse(stripBody(cacheResponse))
          .build();
    }
    }

上述的代码,重要做了几件事:

  1. 假如用户本身设置了缓存拦截器,cacheCandidate = cache.Response 猎取用户本身存储的 Response,不然 cacheCandidate = null,同时从 CacheStrategy 猎取cacheResponse 和 networkRequest;

  2. 假如 cacheCandidate != null 而 cacheResponse == null 申明缓存无效清晰 cacheCandidate 缓存。

  3. 假如 networkRequest == null 申明没有收集,cacheResponse == null 没有缓存,返回失利的信息,义务链此时也就停止,不会在往下继承实行。

  4. 假如 networkRequest == null 申明没有收集,cacheResponse != null 有缓存,返回缓存的信息,义务链此时也就停止,不会在往下继承实行。

上部份代码,实在就是没有收集的时刻的处置惩罚。那末下部份代码肯定是,有收集的时刻处置惩罚:

    // 实行下一个拦截器
    Response networkResponse = null;
    try {
      networkResponse = chain.proceed(networkRequest);
    } finally {
      // If we're crashing on I/O or otherwise, don't leak the cache body.
      if (networkResponse == null && cacheCandidate != null) {
        closeQuietly(cacheCandidate.body());
      }
    }

    // 收集要求 返来 更新缓存
    // If we have a cache response too, then we're doing a conditional get.
    // 假如存在缓存 更新
    if (cacheResponse != null) {
      // 304相应码 自从上次要求后,要求须要相应的内容未发作转变
      if (networkResponse.code() == HTTP_NOT_MODIFIED) {
        Response response = cacheResponse.newBuilder()
            .headers(combine(cacheResponse.headers(), networkResponse.headers()))
            .sentRequestAtMillis(networkResponse.sentRequestAtMillis())
            .receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
            .cacheResponse(stripBody(cacheResponse))
            .networkResponse(stripBody(networkResponse))
            .build();
        networkResponse.body().close();

        // Update the cache after combining headers but before stripping the
        // Content-Encoding header (as performed by initContentStream()).
        cache.trackConditionalCacheHit();
        cache.update(cacheResponse, response);
        return response;
      } else {
        closeQuietly(cacheResponse.body());
      }
    }
    // 缓存Response
    Response response = networkResponse.newBuilder()
        .cacheResponse(stripBody(cacheResponse))
        .networkResponse(stripBody(networkResponse))
        .build();

    if (cache != null) {
      if (HttpHeaders.hasBody(response) && CacheStrategy.isCacheable(response, networkRequest)) {
        // Offer this request to the cache.
        CacheRequest cacheRequest = cache.put(response);
        return cacheWritingResponse(cacheRequest, response);
      }

      if (HttpMethod.invalidatesCache(networkRequest.method())) {
        try {
          cache.remove(networkRequest);
        } catch (IOException ignored) {
          // The cache cannot be written.
        }
      }
    }

    return response;
  }

 上面的代码重要做了这几件事:

  1. 实行下一个拦截器,也就是要求收集

  2. 义务链实行终了后,会返回终究相应数据,假如缓存存在更新缓存,假如缓存不存在到场到缓存中去。

这就跟前面讲的对应上了,要求前做一些处置惩罚,比方推断缓存是不是存在,收集是不是可用等操纵;数据返来以后,更新缓存,在传给上一个拦截器去做处置惩罚。

如许就表现出了义务链的好处了,当义务链实行终了,假如拦截器想要拿到终究的数据做其他的逻辑处置惩罚等,如许就不必在做其他的挪用要领逻辑了,直接在当前的拦截器就能够拿到终究的数据。这也是okhttp设想的最文雅最中心的功用。

到这里,异步要求逻辑基础就梳理完了。

同步要求

同步要求会直接挪用 Call#ececute 要领,记着这个 execute 要领的返回实体是 Reponse,所以它直接返回了要求。 

// RealCall
// 同步实行要求 直接返回一个要求的效果
  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    // 挪用监听的最先要领
    eventListener.callStart(this);
    try {
      // 添加到行列中去
      client.dispatcher().executed(this);
      // 猎取要求的返回数据
      Response result = getResponseWithInterceptorChain();
      if (result == null) throw new IOException("Canceled");
      return result;
    } catch (IOException e) {
      eventListener.callFailed(this, e);
      throw e;
    } finally {
      // 实行调理器的完成要领 移除行列
      client.dispatcher().finished(this);
    }
  }

重要做了几件事:

  1. synchronized (this) 防止反复实行,上面的文章部份有讲。

  2. client.dispatcher().executed(this),现实上调理器只是将 call 到场到了同步实行行列中。

  3. getResponseWithInterceptorChain() 最中心的代码,相当于同步要求直接就最先运转,要求收集获得相应数据,返回给用户

  4. client.dispatcher().finished(this);  实行调理器的完成要领 移除行列

能够看出,在同步要求的要领中,涉及到 dispatcher 只是告知了实行状况,最先实行了(挪用 executed),实行终了了(挪用 finished)其他的并没有涉及到。dispatcher 更多的是效劳异步要求。

以上就是对 Okhttp 要求流程的梳理,背面附一张盗的流程图

 

 

  选择打赏方式
微信赞助

打赏

QQ钱包

打赏

支付宝赞助

打赏

  移步手机端
Okhttp 要求流程梳理

1、打开你手机的二维码扫描APP
2、扫描左则的二维码
3、点击扫描获得的网址
4、可以在手机端阅读此文章
未定义标签

本文来源:搜奇网

本文地址:https://www.sou7.cn/282312.html

关注我们:微信搜索“搜奇网”添加我为好友

版权声明: 本文仅代表作者个人观点,与本站无关。其原创性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容、文字的真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。请记住本站网址https://www.sou7.cn/搜奇网。

发表评论

选填

必填

必填

选填

请拖动滑块解锁
>>