46

android-网络框架解析–第一篇OkHttp,请求与响应流程

 3 years ago
source link: http://www.demanmath.com/index.php/2020/09/12/android-wangluokuangjiajiexi-diyipianokhttpqingqiuyuxiangyingliucheng/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

概述

整个过程从OKHttp开始,来一步步分析,如何使用网络框架来搭建网络框架问题,已经优缺点。

先来看整体框架:

u2mAneM.png!mobile

OkHttp的源码分析,请求

OkHttp的请求

@Override public Call newCall(Request request) {
    return RealCall.newRealCall(this, request, false /* for web socket */);
  }

从源码看,这里是一个封装而已。

同步和异步请求

excute & enqueue

从架构设计图来看,他们最终都会调用到excute。

so,我们先来看enqueue的方法。

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

关键是最后一句,有个diapatcher,然后在放到enqueue里面。

public final class Dispatcher

所以client.dispatcher()就是这个类,而且它是final的,不会有子类。

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

简单看下,就是放入队列的操作。executorService,java的线程池。就是这么简单的操作。

所以整合网络请求还是call自己干的活。

然后我们来分析下AsyncCall

AsyncCall

final class AsyncCall extends NamedRunnable {
    private final Callback responseCallback;

    AsyncCall(Callback responseCallback) {
      super("OkHttp %s", redactedUrl());
      this.responseCallback = responseCallback;
    }

    String host() {
      return originalRequest.url().host();
    }

    Request request() {
      return originalRequest;
    }

    RealCall get() {
      return RealCall.this;
    }

    @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 {
          eventListener.callFailed(RealCall.this, e);
          responseCallback.onFailure(RealCall.this, e);
        }
      } finally {
        client.dispatcher().finished(this);
      }
    }
  }

上来就是NamedRunnable。看了下,什么都没干,就是直接run execute。所以上面这段execute就是网络请求的代码。

what?那http呢,怎么没有看到对应的网络请求在哪里?

Response response = getResponseWithInterceptorChain();

有干货的就这一句话。

好,我们先分析到这里,然后重新开始分析RealCall的execute的方法。

RealCall:execute

@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);
    }
  }

如果不仔细看的化,从RealCall的execute方法,和AsyncCall的execute的方法基本一致。关键都是这一句:

Response result = getResponseWithInterceptorChain();

所以OKHttp的请求的关键到了,就是Response result = getResponseWithInterceptorChain();

getResponseWithInterceptorChain

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);
  }

短短几句话,把OKHttp的精髓都囊括了。就是interceptor的这个设计。

首先它是ArrayList,所以是顺序执行的。

RealInterceptorChain

又是一个final的类,很好。

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, call, eventListener, connectTimeout, readTimeout,
        writeTimeout);
    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");
    }

    if (response.body() == null) {
      throw new IllegalStateException(
          "interceptor " + interceptor + " returned a response with no body");
    }

    return response;
  }

所以这句chain.proceed调用的是next的 interceptor

如果中间打断了这个过程,那它就处理完了这个结果,如果没有,就会一直找到next one去处理。

这段代码很精巧。

从这个思路去对比 android的事件分发机制,最先获取的对象,可以自己判定是自己来interceptor事件,还是继续分发下去。

这里我们再来回过头来去看整体框架,就会发现,这个顺序就是在getResponseWithInterceptorChain里面实现的。

zu6Zf2n.png!mobile

图中的链路和代码分析的结果是一致的。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK