Okhttp原理

2019-11-08  本文已影响0人  晓晓桑

异步get

    private void getData() {

        String url = "https://wwww.baidu.com";

        OkHttpClient okHttpClient = new OkHttpClient.Builder()
                .build();

        final Request request = new Request.Builder()
                .url(url)
                .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());
            }
        });
    }
call.enqueue():
@Override public void enqueue(Callback responseCallback) {
    synchronized (this) {
    //call是否被执行过
      if (executed) throw new IllegalStateException("Already Executed");
      executed = true;
    }
    captureCallStackTrace();
    eventListener.callStart(this);
    client.dispatcher().enqueue(new AsyncCall(responseCallback));
  }
client.dispatcher()
//在public class OkHttpClient类下
  public Dispatcher dispatcher() {
    return dispatcher; //dispatcher在OkHttpClient的Builder()的时候已经初始化
  }
client.dispatcher().enqueue
  synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

enqueue()总结:
1.判断当前call是否执行过;
2.把传过来等call封装成一个AsyncCall对象,AsyncCall其实就是一个runnable
3.client.dispatcher().enqueue()进行异步请求:当正在请求当runnable个数小于64并且当前网络请求当host小于5个请求当时候,这时会把runnable放到请求异步队列当中,然后通过线程池去执行call的请求。如果不是,会把runnable添加到等待就绪当异步请求队列当中。

线程池执行call请求
@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);
      }
    }

判断请求重定向(retryAndFollowUpInterceptor)是否被取消,如果被取消,回调onFailure;如果没有被取消,回调onResponse。最后调用client.dispatcher().finished(this)

client.dispatcher().finished(this)
  void finished(AsyncCall call) {
    finished(runningAsyncCalls, call, true);
  }
  private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
    int runningCallsCount;
    Runnable idleCallback;
    synchronized (this) {
      //把当前的call从运行的runnable里移除
      if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
    //调整正在异步请求的队列,把待请求的call加入进去
      if (promoteCalls) promoteCalls();
      //重新计算正在请求的线程数
      runningCallsCount = runningCallsCount();
      idleCallback = this.idleCallback;
    }
    if (runningCallsCount == 0 && idleCallback != null) {
      idleCallback.run();
    }
  }

okhttp的任务调度

okhttp如何实现同步和异步请求?

发送的同步/异步请求都会在dispatcher中管理其状态

dispatcher的作用

维护请求的状态,维护一个线程池,用于执行请求。

public final class Dispatcher {
···
//维护了一个异步高效的线程池来执行网络操作
  private @Nullable ExecutorService executorService;
//就绪状态的异步请求状态
  private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
//正在执行的的异步请求,包含:已经取消,但是没有执行完的请求
  private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();

  private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
}

okhttp的拦截器

上一篇 下一篇

猜你喜欢

热点阅读