- 介绍
- 使用
- 分发器
OkHttp是目前Android 使用最广泛的网络框架,包括Android4.4以后,HttpURLConnection的底层也是采用OkHttp的。甚至目前部分Java也使用OkHttp。
特点:
1. 支持HTTP2,对同一台服务器的所有请求可以共享同一个套接字(socket)。
2. 如果是非HTTP2,则可以通过连接池,降低请求延迟(内置有连接池,支持复用)。
3. 支持GZip压缩响应体。并默认适用GZip。
4. 通过缓存技术避免重复的网络请求。
简单讲讲里面的一些逻辑。我们常听说OSI七层模型。HTTP是处于 应用层 上,他是网络服务与最终用户的一个接口,他负责数据的收发,DNS解析等。用于会话的。有了会话之后,就需要进行传输。这时候就会用到 传输层TCP。 期间会经历表示层(对数据的表示进行修改,比如压缩)和会话层(建立,管理,终止会话)。每次通讯,都需要一个TCP连接。OkHttp就以连接池技术来实现对建立的TCP进行管理,这样就比重新建立TCP连接要快很多。TCP传输则需要通过 网络层IP 进行寻址(其实socket就是对这边的TCP/IP抽象的实现,所以只要把socket缓存起来,就能共享)。然后程序中就能通过socket的OutputStream将报文发出去。
OkHttp默认会询问服务器是否支持GZip压缩,如果支持,则服务器会使用GZip去压缩数据。
如果我们开启了缓存机制,则OkHttp会按HTTP协议规则去缓存我们的相应数据。HTTP支持强缓存和协商缓存。当OkHttp再次请求的时候,回先去缓存区看看是否存在缓存。再决定是否需要请求服务器。
// 导包,这里导入的是3.21.1
implementation 'com.squareup.okhttp3:okhttp:3.12.1'
// 构建OkHttpClient,两种方法都行。初始化的东西都是一样的。
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
// OkHttpClient okHttpClient = new OkHttpClient();
// 构造请求Request对象
Request request = new Request.Builder()
.url(url)
.get() //默认就是GET请求,可以省略
.build();
// 通过OkHttpClient和Request构建Call对象
Call call = okHttpClient.newCall(request);
// 1.利用Call调用enqueue(Callback)方法来执行**异步请求**,顾名思义:enqueue是将请求丢入Deque双端队列里。 源码进行了请求判定,一个call只能使用一次(比较简单,可以自己看看)。
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// TODO 请求失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// TODO 获得服务器返回数据
}
});
// 2.也可以利用Call调用execute方法,execute是同步请求
Response response = call.execute();
代码初看:
1.OkHttpClient初始化
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
// 在Builder()里面初始化了OkHttpClient所需要的一些默认属性和方法。
public Builder() {
dispatcher = new Dispatcher(); // 默认分发器
protocols = DEFAULT_PROTOCOLS; // 实现协议
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE); // 事件监听器工厂,用于创建事件监听器
proxySelector = ProxySelector.getDefault(); // 代理选择器
if (proxySelector == null) {
proxySelector = new NullProxySelector(); // 代理选择器
}
cookieJar = CookieJar.NO_COOKIES; // cookie策略化和持久化方案
socketFactory = SocketFactory.getDefault(); // socket工厂
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE; // 代理服务器认证
authenticator = Authenticator.NONE; // 服务器认证方式
connectionPool = new ConnectionPool(); // 连接池
dns = Dns.SYSTEM; // 系统DNS解析器
followSslRedirects = true; // 是否从HTTP重定向到HTTPS
followRedirects = true; // 是否重定向
retryOnConnectionFailure = true; //连接失败时是否重连
callTimeout = 0; //请求超时
connectTimeout = 10_000; // 连接超时
readTimeout = 10_000; // 读超时
writeTimeout = 10_000; // 写超时
pingInterval = 0; //服务器每次发ping指令的时间间隔
}
2.Request初始化
Request request = new Request.Builder()
.url("")
.get() //默认就是GET请求,可以省略
.build();
3.Call初始化
Call call = okHttpClient.newCall(request);
@Override
public Call newCall(Request request) {
// Call 是接口,所以返回的是Call的实现类的实例化对象
return RealCall.newRealCall(this, request, false );
}
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// 初始化Call,
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
4.接下来是分发器的内容了
分发器OkHttp分发器:Dispatcher(package okhttp3)。当然我们在构建OkHttpClient 的时候,也可以传入自定义的分发器。
// 传入自定义分发器 OkHttpClient okHttpClient = new OkHttpClient.Builder().dispatcher(dispatcher).build();
// 调用异步的方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// TODO 请求失败
}
@Override
public void onResponse(Call call, Response response) throws IOException {
// TODO 获得服务器返回数据
}
});
// 异步方法主要实现,传入回调函数
@Override
public void enqueue(Callback responseCallback) {
// 对该对象进行同步,这边相当于给call加上executed是否执行过的标记,如果调用过一次,则该call不能再调用,需要重新创建或者clone(),才能再调用。
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
// eventListener可以监听OkHttp各个步骤的开始或者完成时间节点,可以用来记录各个节点的执行时间。
eventListener.callStart(this);
// okhttpclient获取到分发器(dispatcher),然后调取该分发器的enqueue()方法,传入异步请求任务AsyncCall
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
void enqueue(AsyncCall call) {
synchronized (this) {
readyAsyncCalls.add(call);
}
// 提升权限并执行,这里面是,给准备队列中的call提升至运行队列
promoteAndExecute();
}
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
List executableCalls = new ArrayList<>();
boolean isRunning;
synchronized (this) {
// 遍历准备队列中的call
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall asyncCall = i.next();
// 判断运行中的call 是否大于maxRequests 可以设置
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
// 判断同一域名下的请求是否大于maxRequestsPerHost 可以设置
if (runningCallsForHost(asyncCall) >= maxRequestsPerHost) continue; // Host max capacity.
// 从readyAsyncCalls移出
i.remove();
executableCalls.add(asyncCall);
// 添加到runningAsyncCalls队列
runningAsyncCalls.add(asyncCall);
}
isRunning = runningCallsCount() > 0;
}
for (int i = 0, size = executableCalls.size(); i < size; i++) {
//AsyncCall 能调用线程池的
AsyncCall asyncCall = executableCalls.get(i);
// executorService 线程池。最后会从runningAsyncCalls队列取出交给线程池执行
asyncCall.executeOn(executorService());
}
return isRunning;
}
// 通过线程池获取线程的方法
public synchronized ExecutorService executorService() {
if (executorService == null) {
//
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
// 线程执行asyncCall
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
boolean success = false;
try {
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
eventListener.callFailed(RealCall.this, ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
final class AsyncCall extends NamedRunnable {
...
@Override
protected void execute() {
boolean signalledCallback = false;
timeout.enter();
try {
// 执行拦截器,获取Response
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) {
e = timeoutExit(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 {
// 每当任务执行完,尝试回调promoteAndExecute()去将下一个准备队列中的call加入到running队列中
client.dispatcher().finished(this);
}
}
}
void finished(AsyncCall call) {
finished(runningAsyncCalls, call);
}
private void finished(Deque calls, T call) {
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
idleCallback = this.idleCallback;
}
// 去尝试将下一个准备队列中的call加入到running队列中
boolean isRunning = promoteAndExecute();
if (!isRunning && idleCallback != null) {
idleCallback.run();
}
}



