Okhttp请求
2024-10-21 23:23:34
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();
总结:
创建OkHttpClient和Request对象
将Request封装成Call对象
调用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);
}
});
总结:
创建OkHttpClient和Request对象
将Request封装成Call对象
调用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.
}
}
总结:
通过没有核心线程的线程池执行请求
在finally中正在运行的队列移除请求,并执行等待队列中的可以执行的请求。
参考:
最新文章
- java.io中的System.in、 System.out和System.err
- c# 指定的存储区提供程序在配置中找不到,或者无效
- DragLayout: QQ5.0侧拉菜单的新特效
- [BZOJ2654]tree(二分+MST)
- Jenkins使用jenkins-cli.jar进行远程调用时出现“ERROR: No such job &#39;test&#39;”的问题解决(Windows)
- java获取class所在jar
- squid代理服务器搭建及配置
- 【BZOJ】【1834】【ZJOI2010】Network 网络扩容
- 解决mac os x 10.9.1 AppStore ‘Use the Purchases page to try again’ 问题
- MySQL数据库备份与恢复方法(转)
- 在iOS8下使用CLLocationManager定位服务需要系统授权
- FastReport扩展类
- c++初学(电梯实验)
- shell 处理 文件名本身带星号的情况
- pdf去水印
- Loadrunner Webservice接口性能测试脚本编写优化总结
- 003.Keepalived搭建LVS高可用集群
- Linux 系统查看对应公网映射地址
- Shell基础知识(六)
- C++.构造函数(超出范围)_01