序 、最近因为一些原因 ,会连续记录学习的一些笔记 。
背景
PS:OKHTTP 版本为 3.10.0
api 'com.squareup.okhttp3:okhttp:3.10.0'
get 请求示例代码
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
final Request request = new Request.Builder().url("www.baidu.com").get().build();
Call call = okHttpClient.newCall(request);
同步方法
try {
Response execute = call.execute();
} catch (IOException e) {
e.printStackTrace();
}
异步方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String string = response.body().string();
response.body().byteStream();
}
});
核心类 OkHttpClient 、Request 、Call 、RealCall 、Dispatcher 、Deque 、AsyncCall 、Response 。
流程梳理
1. OkHttpClient 网络配置层
使用构建者模式创建实例 (在后续文章会详细介绍构建者模式)。
OkHttpClient okHttpClient = new OkHttpClient.Builder().build();
下图是此构建者可以 add 的参数配置 。我们平时最常使用的比如添加拦截器操作 ,就是通过此构建者 。
2. Request 当前请求体
使用构建者模式创建实例 (在后续文章会详细介绍构建者模式)。
final Request request = new Request.Builder().url("www.baidu.com").get().build();
3. Call 可以操作异步也可以操作同步 。
Call call = okHttpClient.newCall(request);
我们先来分析一下 Call 对象 ,直接进入 newcall 方法 。如下 ,最终返回的是 RealCall 对象 ,RealCall 是 Call 接口的实现类 。
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
我们直接分析异步方法调用
异步方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String string = response.body().string();
response.body().byteStream();
}
});
4. RealCall 作为 Call 的实现类 ,重写了 Call 的异步方法 enqueue ,我们直接进入 RealCall 类里面查看 enqueue 。
来源 :RealCall
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
我们先来看此方法前三行的加锁代码 ,意思是不能请求两次异步方法 。可以自己写个 demo ,异步方法在写一遍如下 。运行之后一定会报错 Already Executed 。
异步方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String string = response.body().string();
response.body().byteStream();
}
});
异步方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String string = response.body().string();
response.body().byteStream();
}
});
5. RealCall 的 enqueue 方法的最后一行代码 任务调度器 Dispatcher 。
client.dispatcher().enqueue(new AsyncCall(responseCallback));
RealCall 的 enqueue 方法最后调用的是任务调度器 Diaspatcher 的 enqueue 方法 ,会传去一个 AsyncCall 参数 。
任务调度器 Dispatcher 类
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
首先看方法体里面的内容 。有几个参数 。
双端队列 :Deque
运行队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
等待队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
最大请求数量
private int maxRequests = 64;
最大请求 HOST
private int maxRequestsPerHost = 5;
PS:首先我们看方法里面的判断条件 :
runningAsyncCalls.size() < maxRequests 运行队列的数量小于 64 个 ,意思是同时运行的异步任务不能超过 64个 。
runningCallsForHost(call) < maxRequestsPerHost 不能同时访问 5 个 Host端口 。
如果满足以上条件 ,则会被添加到 runningAsyncCalls 队列 。然后在执行 ,否则的话 ,就会被加入等待队列 readyAsyncCalls.add(call) 。
6. 任务调度器传入一个 AsyncCall ,我们来看一下这个类 。
点进去发现 AsyncCall 是 RealCall 的一个内部类 。实现了 NameRunnable 接口 ,接口有实现了 Runnable 。作为一个线程 ,重写 Run 方法 ,并且调用抽象方法 execute 。所以我们来看 AsyncCall 重写的方法 execute 方法 。
RealCall 的内部类 AsyncCall 重写的抽象方法
@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);
}
}
Response response = getResponseWithInterceptorChain();使用责任链模式返回 Response 。这个之后在详细写写 ,在此跳过 。
PS:我们来看一下这个 try catch 。需要注意一个变量 signalledCallback ,在 try 里面无论是走成功还是失败的回调 ,都会把这个变量设置为 true 。然后在 catch 里面 如何为 true 的话 ,就直接打印说是你用户的错 ,跟OKHTTP 无关 ,符合程序员的形象 ,不甩锅也不替别人背锅 。
解释一下 。
如果 是 这行代码 Response response = getResponseWithInterceptorChain(); 发生异常 ,则直接在catch里面走失败回调 。如果已经走过成功失败回调 ,证明 response 是没有问题的 我们可以看下异步回到的方法 。
//异步方法
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String string = response.body().string();
response.body().byteStream();
}
});
在 onResponse 回调中国如果因为我们自己的代码逻辑错误抛出异常 ,则回到 execute 方法中就会到 catch 中 ,然后变量signalledCallback 告诉你这是你自己的问题,不是 OKHTTP 的问题 。
OKOK END 、