OkHttp——Calls

2019-08-18  本文已影响0人  lframe

通过该篇文章大家可以了解到如下几点
1.首先通过一个简单的代码示例了解Call是什么
2.从源码的角度分析一下Call的定义
3.分析一下Call的实现类,从而真正了解Call

首先我们先以一段简短的代码为开头来了解一下Call在我们OkHttp中的作用.

OkHttpClient client = new OkHttpClient();
    String run(String url) throws IOException {
        Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = client.newCall(request);
        try (Response response = call.execute()) {
            return response.body().string();
        }
    }

从上面的代码中我们可以简单地看出,Call 的作用就是执行一个准备好的请求。


接下来我们从Call的定义中了解一下Call到底是什么,下面给出的是Call接口的源码。

public interface Call {
/**
**该方法返回的是原始的请求,也就是我们上面通过client.newCall中注入的Request。
**/
  Request request();
/**
**立即执行该请求,并进入阻塞状态,直到请求处理得到响应或者发生error。
**/
  Response execute() throws IOException;
/**
**异步执行请求,该方法不会被阻塞,在OkHttpClient中的调度器dispatcher定义了该方法请求何时被运行,正常情况下都是立马去执行的,除非目前正在执行其他的请求,在客户端将HTTP得到的响应(失败异常)会调用参数Callback 将其回调出去
**/
  void enqueue(Callback responseCallback);
/**
**取消请求,如果请求已经执行结束了,则无法取消
**/
  void cancel();
/**
**
请求是否已经执行,如果调用了execute()或者enqueue()方法,则返回true
**/
  boolean isExecuted();
/**
**请求是否已取消
**/
  boolean isCanceled();
  interface Factory {
    Call newCall(Request request);
  }
}

从上面的代码中,我们可以了解到Call大致有以下几个功能:

  1. 获取原始请求
  2. 同步阻塞的方式执行请求
  3. 异步分阻塞的方式执行请求
  4. 在请求结束前可以取消请求
  5. 查看当前请求是否被执行
  6. 查看当前请求是否被取消

其实Call只有一个实现类RealCall,我们最上面的代码中通过call.newCall构造的Call就是我们的RealCall。

  @Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }

接下来我们通过它的部分源码了解一下RealCall。

final class RealCall implements Call {
  private final OkHttpClient client;
  private boolean executed;
  volatile boolean canceled;
  Request originalRequest;
/**
**Http执行引擎,也就是真正执行Http请求的类。
**/
  HttpEngine engine;

  @Override public Response execute() throws IOException {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    try {
      client.dispatcher().executed(this);
      Response result = getResponseWithInterceptorChain(false);
      if (result == null) throw new IOException("Canceled");
      return result;
    } finally {
      client.dispatcher().finished(this);
    }
  }


  @Override public void enqueue(Callback responseCallback) {
    enqueue(responseCallback, false);
  }

  void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
  }

  @Override public void cancel() {
    canceled = true;
    if (engine != null) engine.cancel();
  }

  @Override public synchronized boolean isExecuted() {
    return executed;
  }

  @Override public boolean isCanceled() {
    return canceled;
  }

首先看一下我们的execute方法,内部通过synchronized保证每个RealCall只能执行一次execute,而且内部通过dispatcher执行我们的请求,那接下来我们看一下Dispatcher的源码。

public final class Dispatcher {
  private int maxRequests = 64;
  private int maxRequestsPerHost = 5;

  /** Executes calls. Created lazily. */
  private ExecutorService executorService;

  /** 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<>();

  public Dispatcher(ExecutorService executorService) {
    this.executorService = executorService;
  }

从上面的源码可以看出,内部封装了一个线程池和三个队列,分别是准备好的异步Call队列和正在运行的异步Call队列和正在运行的同步Call队列。
那我们看看Dispatcher中对应于RealCall中的executed方法。

  synchronized void executed(RealCall call) {
    runningSyncCalls.add(call);
  }

内部就是将对应的Call加入同步队列。

   1:  Response result = getResponseWithInterceptorChain(false);

   2: private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
    Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
    return chain.proceed(originalRequest);
  }
  3:  通过执行引擎HttpEngine执行请求。
 engine = new HttpEngine(client, request, false, false, forWebSocket, null, null, null);


接下来我们看一下Dispatcher中对应于RealCall中的enqueue方法。

  void enqueue(Callback responseCallback, boolean forWebSocket) {
    synchronized (this) {
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
  }

该方法通过构造一份异步的Call,然后在Dispatcher中的线程池执行。

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

好了,到目前为止,大家已经了解了Call在OkHttp中所起到的作用。

上一篇下一篇

猜你喜欢

热点阅读