theme: juejin
highlight: a11y-dark

同步请求

OkHttpClient httpClient = new OkHttpClient();

String url = "https://www.baidu.com/";
Request getRequest = new Request.Builder()
.url(url)
.get()
.build(); Call call = httpClient.newCall(getRequest); new Thread(new Runnable() {
@Override
public void run() {
try {
//同步请求,要放到子线程执行
Response response = call.execute();
Log.i(TAG, "okHttpGet run: response:"+ response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();

总结:

  1. 创建OkHttpClient和Request对象

  2. 将Request封装成Call对象

  3. 调用Call的execute()发送同步请求

同步执行流程

第一步,创建一个OkHttpClient对象

OkHttpClient mClient = new OkHttpClient.Builder().build();
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
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;
}

重点关注Dispatcher、ConnectionPool的初始化。Dispatcher和异步请求有关,我们先不讲,我们重要讲一下ConnectionPool。

ConnectionPool有两个作用:

作用一,当你请求的url是相同的时候,就可以复用这个Connection;

作用二,ConnectionPool可以设置哪些Connection保持打开,哪些Connection可以保持复用;

第二步,创建携带请求信息的Request对象

Request request = new Request.Builder().url("http://www.baidu.com").get().build();

Builder(Request request) {
this.url = request.url;
this.method = request.method;
this.body = request.body;
this.tag = request.tag;
this.headers = request.headers.newBuilder();
}

第三步,创建Call对象

@Override public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
} RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
final EventListener.Factory eventListenerFactory = client.eventListenerFactory(); this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
(1)重定向拦截器
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket); // TODO(jwilson): this is unsafe publication and not threadsafe.
this.eventListener = eventListenerFactory.create(this);
}

第四步,call.execute()

@Override public Response execute() throws IOException {
(1)通过标注位一个请求只能执行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
(2)捕捉堆栈信息
captureCallStackTrace();
try {
(3)将请求加入同步队列
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} finally {
(4)移除请求
client.dispatcher().finished(this);
}

private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
(1)移除请求
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();
}
}

异步请求

 String url = "https://www.jianshu.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) { } @Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse() returned: " + response);
}
});

总结:

  1. 创建OkHttpClient和Request对象

  2. 将Request封装成Call对象

  3. 调用Call的enqueue()发送异步请求

异步请求执行流程

前三步和同步一样,不在分析。

第四步,call.enqueue()

@Override public void enqueue(Callback responseCallback) {
(1)通过标注位一个请求只能执行一次
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}

正在异步请求数小于64并且当前url的host请求数小于5就放到正在运行的异步队列,否则放到等待的异步队列。

通过线程池运行AsyncCall。

public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
(1)重点关注
client.dispatcher().finished(this);
}
}
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
(1)移除当前请求
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
(2)执行等待队列中的请求
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
} if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
} 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.
}
}

总结:

  1. 通过没有核心线程的线程池执行请求

  2. 在finally中正在运行的队列移除请求,并执行等待队列中的可以执行的请求。

参考:

最新文章

  1. java.io中的System.in、 System.out和System.err
  2. c# 指定的存储区提供程序在配置中找不到,或者无效
  3. DragLayout: QQ5.0侧拉菜单的新特效
  4. [BZOJ2654]tree(二分+MST)
  5. Jenkins使用jenkins-cli.jar进行远程调用时出现“ERROR: No such job &#39;test&#39;”的问题解决(Windows)
  6. java获取class所在jar
  7. squid代理服务器搭建及配置
  8. 【BZOJ】【1834】【ZJOI2010】Network 网络扩容
  9. 解决mac os x 10.9.1 AppStore ‘Use the Purchases page to try again’ 问题
  10. MySQL数据库备份与恢复方法(转)
  11. 在iOS8下使用CLLocationManager定位服务需要系统授权
  12. FastReport扩展类
  13. c++初学(电梯实验)
  14. shell 处理 文件名本身带星号的情况
  15. pdf去水印
  16. Loadrunner Webservice接口性能测试脚本编写优化总结
  17. 003.Keepalived搭建LVS高可用集群
  18. Linux 系统查看对应公网映射地址
  19. Shell基础知识(六)
  20. C++.构造函数(超出范围)_01

热门文章

  1. 解决pycharm中cv2报错问题,anaconda安装opencv
  2. history 添加 时间戳和ip,用户
  3. ObjectARX2016-2创建直线
  4. pdf2docx:可将 PDF 转换成 docx 文件的 Python 库
  5. C# 调用c库
  6. 安装gitlab的总结
  7. adobe 色轮
  8. 在 RedHat 和 CentOS安装 Sphinx packages
  9. jenkins 设置Git SSH凭证后,构建Git更新报错returned status code 128解决
  10. CF446D 题解