美文网首页
OkHttp——Calls

OkHttp——Calls

作者: lframe | 来源:发表于2019-08-18 22:25 被阅读0次

    通过该篇文章大家可以了解到如下几点
    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中所起到的作用。

    相关文章

      网友评论

          本文标题:OkHttp——Calls

          本文链接:https://www.haomeiwen.com/subject/bvfrsctx.html