目录
①:首先创建一个OkHttpClient对象,这个对象用来统领一切的功能组件。
②:通过Request类的静态方法把访问网络的各种条件封装成一个Request对象。
分析源码,首先导入相应的包,OkHttpClient包和Okio包。
下载地址(当然也可以从github导入)
1.OkHttp简介
OkHttp是一个用于Android的网络框架。比起早期的HttpClient,OkHttp有更灵活的使用方式,支持http和https。许多知名的框架,例如retrofit底层也是通过封装OkHttp来实现的。
OkHttp的有两个特色。一是它请求时的效率非常高,可以重用socket连接。二是OkHttp拥有非常实用的拦截器链,底层通过巧妙的方式实现。可以说理解了OkHttp的拦截器链,也就理解了OkHttp的核心思想。
2.阻塞方式使用OkHttp
//阻塞请求方式
public static void blockRequest() throws IOException {
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
//封装request
Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
//封装call
Call call = okHttpClient.newCall(request);
//阻塞请求方式
Response response = call.execute();
System.out.println("run: " + response.body().string());
System.out.println("success");
}
这是一段特别基础的代码,功能就是访问一下百度的主页,然后打印一下结果(我是直接使用Java测试,所以打印方式就选择了system.out.println)。
①:首先创建一个OkHttpClient对象,这个对象用来统领一切的功能组件。
看看OkHttpClient的代码吧
public class OkHttpClient implements Cloneable, Factory, okhttp3.WebSocket.Factory {
static final List<Protocol> DEFAULT_PROTOCOLS;
static final List<ConnectionSpec> DEFAULT_CONNECTION_SPECS;
//任务调度器
final Dispatcher dispatcher;
@Nullable
final Proxy proxy;
final List<Protocol> protocols;
final List<ConnectionSpec> connectionSpecs;
//全局拦截器拦截器链
final List<Interceptor> interceptors;
//network拦截器链
final List<Interceptor> networkInterceptors;
final okhttp3.EventListener.Factory eventListenerFactory;
final ProxySelector proxySelector;
final CookieJar cookieJar;
@Nullable
final Cache cache;
@Nullable
final InternalCache internalCache;
final SocketFactory socketFactory;
final SSLSocketFactory sslSocketFactory;
final CertificateChainCleaner certificateChainCleaner;
final HostnameVerifier hostnameVerifier;
final CertificatePinner certificatePinner;
final Authenticator proxyAuthenticator;
final Authenticator authenticator;
final ConnectionPool connectionPool;
final Dns dns;
final boolean followSslRedirects;
final boolean followRedirects;
final boolean retryOnConnectionFailure;
final int callTimeout;
final int connectTimeout;
final int readTimeout;
final int writeTimeout;
final int pingInterval;
....
}
哇塞,好庞大的类。OkHttp整个框架的所有核心功能组件都在这里面了,连接池、各种超时时间、各种组件工厂等等都定义在这里。可以说OkHttpClient类是整个框架的核心。
这篇文章主要会运用三个加注释的属性,任务调度器Dispatcher和两个拦截器集合。
②:通过Request类的静态方法把访问网络的各种条件封装成一个Request对象。
public final class Request {
final HttpUrl url;
final String method;
final Headers headers;
@Nullable
final RequestBody body;
final Map<Class<?>, Object> tags;
@Nullable
private volatile CacheControl cacheControl;
....
}
可以看到Request对象更像一个JavaBean实体,它描述了一个请求的模型,功能上与JavaEE中封装Request类似。
③:把Request对象封装为Call对象。
Call是一个接口,这里用的是它的实现类RealCall。这个类的功能类似于一个终端的功能,里面封装了调用核心网络请求功能的方法。这个类把用户与核心功能接口进行了解耦,用户只需操作RealCall这个类即可以使用相应的方法进行网络请求。
来看看这个类吧。
final class RealCall implements Call {
final OkHttpClient client;
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;
final AsyncTimeout timeout;
@Nullable
private EventListener eventListener;
final Request originalRequest;
final boolean forWebSocket;
private boolean executed;
...
}
类中包含了指向OkHttpClient的引用,Request对象和其他的功能组件。大体可以猜得出在RealCall的方法中通过调用这些对象的核心功能方法来进行网络访问。
④:操作Call对象
继续往下看,现在重头戏要来了,先总结一下上面的知识,以免混乱。
首先创建了OkHttpClient对象,其中封装了访问网络的核心代码。接着把访问网络的各类参数封装成一个Request。然后把Request封装为一个Call对象,这个Call类有很多的功能组件,并且把用户操作和核心功能代码进行了解耦。
现在要开始操作Call对象来进行网络访问了。
阻塞方式请求通过调用Call对象中的execute方法实现的。
先看看execute方法吧
public Response execute() throws IOException {
synchronized(this) {
if (this.executed) {
throw new IllegalStateException("Already Executed");
}
this.executed = true;
}
this.captureCallStackTrace();
this.timeout.enter();
this.eventListener.callStart(this);
Response var2;
//重点代码区
try {
//调用OkHttpClient中的dispatcher对象的executed方法执行操作
this.client.dispatcher().executed(this);
//执行拦截器链
Response result = this.getResponseWithInterceptorChain();
if (result == null) {
throw new IOException("Canceled");
}
var2 = result;
} catch (IOException var7) {
IOException e = this.timeoutExit(var7);
this.eventListener.callFailed(this, e);
throw e;
} finally {
//把任务出队
this.client.dispatcher().finished(this);
}
return var2;
}
首先它会执行一些辅助操作,判断是否可以执行操作,设置超时时间,执行注册的监听器。
然后是两个重量级操作
A.调用OkHttpClient中的Dispatchar对象的executed方法操作Call对象,并把自己传入(this.client.dispatcher().executed(this);)
dispatcher()方法是返回OkHttpClient类中的Dispatcher任务调度器组件。
这个Dispatchar是什么来头呢?来看看它的代码
public final class Dispatcher {
private int maxRequests = 64;//最大请求数量
private int maxRequestsPerHost = 5;//每台主机最大的请求数量
@Nullable
private Runnable idleCallback;
@Nullable
private ExecutorService executorService;//任务执行线程池
//准备执行的请求队列
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque();
//正在运行的请求队列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque();
//正在运行的同步请求队列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque();
...
}
通过这些变量不难发现,Dispatcher通过三个请求队列来管理和调度请求,在通过一个线程池去并发执行请求。
接着看它的executed()方法。
synchronized void executed(RealCall call) {
this.runningSyncCalls.add(call);
}
就一行代码,把传入的Call对象加入请求队列,因为现在是通过阻塞请求的方法访问网络,因此加入runningSynCalls中。而且ArrayDeque并不是线程安全的,因此该方法用synchronized关键件修饰了。
之后不管任务执行如果,都要出队。
这样第一个重量级代码就完毕了。
B.执行拦截器链( Response result = this.getResponseWithInterceptorChain())
这一行代码我看了一下午。可见它的重要性,我称它为重量级代码S。
首先有一个问题,什么是拦截器。
拦截器是我们在执行相应操作之前进行的一个检查操作。就像坐飞机之前要安检,只有安检通过才能进入候机大厅。
OkHttp添加拦截器可以在创建OkHttpClient对象时直接添加。
OkHttpClient okHttpClient = new OkHttpClient.Builder()
//通过Builder方法和addInterceptor方法组合添加拦截器
.addInterceptor(new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
long startTime = System.nanoTime();
System.out.println(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
//放行函数
Response response = chain.proceed(request);
long endTime = System.nanoTime();
System.out.println( String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (endTime - startTime) / 1e6d, response.headers()));
//返回response对象
return response;
}
})
.build();
我是直接通过匿名内部类添加拦截器,也可以直接写一个类去作为拦截器,实现Interceptor接口就OK。
public interface Interceptor {
Response intercept(Interceptor.Chain var1) throws IOException;
public interface Chain {
Request request();
Response proceed(Request var1) throws IOException;
@Nullable
Connection connection();
Call call();
int connectTimeoutMillis();
Interceptor.Chain withConnectTimeout(int var1, TimeUnit var2);
int readTimeoutMillis();
Interceptor.Chain withReadTimeout(int var1, TimeUnit var2);
int writeTimeoutMillis();
Interceptor.Chain withWriteTimeout(int var1, TimeUnit var2);
}
}
这个接口只有一个抽象方法interceptor(),在执行拦截器时会运行这个方法。其中还有一个Chain接口,这个接口是interceptor方法参数类型,后面会说到他。
现在来看看 getResponseWithInterceptorChain()这个函数吧。
Response getResponseWithInterceptorChain() throws IOException {
//定义一个拦截器集合,记录所有存在的拦截器
List<Interceptor> interceptors = new ArrayList();
//把OkHttpClient中的全局拦截器加入集合
interceptors.addAll(this.client.interceptors());
//加入一些必要的功能拦截器(这些拦截器是框架本身写好的,用于实现cookies和缓存等功能)
interceptors.add(this.retryAndFollowUpInterceptor);
interceptors.add(new BridgeInterceptor(this.client.cookieJar()));
interceptors.add(new CacheInterceptor(this.client.internalCache()));
interceptors.add(new ConnectInterceptor(this.client));
//如果该请求不是web请求就加入network拦截器
if (!this.forWebSocket) {
interceptors.addAll(this.client.networkInterceptors());
}
//加入最终执行操作对象
interceptors.add(new CallServerInterceptor(this.forWebSocket));
//生成链对象
Chain chain = new RealInterceptorChain(interceptors, (StreamAllocation)null, (HttpCodec)null, (RealConnection)null, 0, this.originalRequest, this, this.eventListener, this.client.connectTimeoutMillis(), this.client.readTimeoutMillis(), this.client.writeTimeoutMillis());
//执行链对象,把最初封装好的Request对象传入
return chain.proceed(this.originalRequest);
}
这个函数太重要了,重要到我几乎每一行都写了注释
就如注释中写的,定义一个拦截器集合,把所有注册的拦截器都加入,以便之后遍历这个集合执行拦截器。
这里要注意,拦截器加入的顺序必须要保持严格的顺序,因为之后的遍历是顺序遍历,错误的插入顺序会导致操作流程异常。
还有一个点,就是“最终执行操作对象”,这里先买个关子。
跟着代码走,接着通过集合生成了Chain对象,Chain是个接口,定义在Interceptor接口中,这里用他的实现类RealInterceptorChain。
看看这个类中有些什么。
public final class RealInterceptorChain implements Chain {
//拦截器集合
private final List<Interceptor> interceptors;
private final StreamAllocation streamAllocation;
private final HttpCodec httpCodec;
private final RealConnection connection;
//当前执行的拦截器的下标
private final int index;
private final Request request;
private final Call call;
private final EventListener eventListener;
private final int connectTimeout;
private final int readTimeout;
private final int writeTimeout;
private int calls;
...
}
又有很多组件,就目前已知的,有拦截器集合,执行拦截器的下标,Request,Call对象。还有很多第一次见到的组件(streamAllocation,HttpCodec这些),之后慢慢了解也不迟,因为在生成RealInterceptorChain都在构造函数中传入的都是空值,所以目前他们都是null。
接着调用它的proceed方法。
public Response proceed(Request request) throws IOException {
//调用重载方法
return this.proceed(request, this.streamAllocation, this.httpCodec, this.connection);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec, RealConnection connection) throws IOException {
//判断下标是否越界
if (this.index >= this.interceptors.size()) {
throw new AssertionError();
} else {
++this.calls;
if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must retain the same host and port");
} else if (this.httpCodec != null && this.calls > 1) {
throw new IllegalStateException("network interceptor " + this.interceptors.get(this.index - 1) + " must call proceed() exactly once");
} else {
//又创建一个链对象,并把当前对象的组件传入(可以理解为保持当前对象状态)
RealInterceptorChain next = new RealInterceptorChain(this.interceptors, streamAllocation, httpCodec, connection, this.index + 1, request, this.call, this.eventListener, this.connectTimeout, this.readTimeout, this.writeTimeout);
//通过下标获得相应的拦截器
Interceptor interceptor = (Interceptor)this.interceptors.get(this.index);
//执行interceptor方法,传入链对象
Response response = interceptor.intercept(next);
if (httpCodec != null && this.index + 1 < this.interceptors.size() && next.calls != 1) {
throw new IllegalStateException("network interceptor " + interceptor + " must call proceed() exactly once");
} else if (response == null) {
throw new NullPointerException("interceptor " + interceptor + " returned null");
} else if (response.body() == null) {
throw new IllegalStateException("interceptor " + interceptor + " returned a response with no body");
} else {
return response;
}
}
}
}
代码很多,但如果无视它的各种异常判断,只有三行代码(究极重要)。
首先又创建了一个拦截器链对象,并把当前链对象的状态复制到新对象中(index加一之后传入)。
接着通过index获得对于拦截器。
执行拦截器的intercept方法,传入新的链对象。
现在可以往上滑看看之前贴的Interception接口和拦截器的实现那些代码。我们Interception接口的intercept方法需要一个Chain对象,并且如果拦截器条件判断成功,就执行Chain对象的proceed放行函数,表示已经成功通过这次检查。那么接下来会发生什么事情呢?看看上面这个函数的函数名,不就是proceed吗?proceed函数中是继续新建Chain对象,根据下标获得interception对象,执行intercept方法,传入新的Chain对象,如果通过检查就调用放行函数proceed。然后继续这样的操作,一直递归执行下去,除了每次获得Interception对象不同以外都是一样的操作。
为了更好的理解,我决定画个图
就像图中所示一样proceed方法和intercept方法交替执行遍历整个拦截器集合。
这其中OkHttp框架把cookies操作,缓存操作等功能也做成了相应的拦截器加入了拦截器集合,在遍历集合的过程中也就顺便对这些方面做了处理,真是非常棒的设计思想。
现在来说说之前卖的关子。最终执行对象CallServerInterceptor,最后的一个拦截器究竟是干什么的。如果大家一路跟下来,就会发现我们目前把所有前置操作都做完了,我们使用这个框架的目的就是为了进行网络请求,那么网络请求的代码在哪呢?在最上层的execute函数,执行完拦截器链就返回response对象了。因此这最后一个拦截器就是真正的执行网络请求操作的代码,OkHttp把它做成了拦截器,放在拦截器链的末尾,如果前面的拦截都被放行,那么就执行最后的操作。
看看CallServerInterceptor类的intercept方法究竟干了什么。
public Response intercept(Chain chain) throws IOException {
RealInterceptorChain realChain = (RealInterceptorChain)chain;
//取得网络操作核心对象
HttpCodec httpCodec = realChain.httpStream();
//取得流分配对象
StreamAllocation streamAllocation = realChain.streamAllocation();
//获取网络连接
RealConnection connection = (RealConnection)realChain.connection();
//获得最初封装的Request对象
Request request = realChain.request();
long sentRequestMillis = System.currentTimeMillis();
realChain.eventListener().requestHeadersStart(realChain.call());
//请求头设置
httpCodec.writeRequestHeaders(request);
realChain.eventListener().requestHeadersEnd(realChain.call(), request);
Builder responseBuilder = null;
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
//网络请求(一切的一切都是为这行代码服务的)
httpCodec.flushRequest();
realChain.eventListener().responseHeadersStart(realChain.call());
//获得响应,封装为responseBuilder 对象
responseBuilder = httpCodec.readResponseHeaders(true);
}
if (responseBuilder == null) {
realChain.eventListener().requestBodyStart(realChain.call());
long contentLength = request.body().contentLength();
CallServerInterceptor.CountingSink requestBodyOut = new CallServerInterceptor.CountingSink(httpCodec.createRequestBody(request, contentLength));
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
realChain.eventListener().requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
} else if (!connection.isMultiplexed()) {
streamAllocation.noNewStreams();
}
}
httpCodec.finishRequest();
if (responseBuilder == null) {
realChain.eventListener().responseHeadersStart(realChain.call());
responseBuilder = httpCodec.readResponseHeaders(false);
}
//取得Response对象
Response response = responseBuilder.request(request).handshake(streamAllocation.connection().handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();
//通过响应码判断本次网络请求的结果
int code = response.code();
if (code == 100) {
responseBuilder = httpCodec.readResponseHeaders(false);
response = responseBuilder.request(request).handshake(streamAllocation.connection().handshake()).sentRequestAtMillis(sentRequestMillis).receivedResponseAtMillis(System.currentTimeMillis()).build();
code = response.code();
}
realChain.eventListener().responseHeadersEnd(realChain.call(), response);
if (this.forWebSocket && code == 101) {
response = response.newBuilder().body(Util.EMPTY_RESPONSE).build();
} else {
response = response.newBuilder().body(httpCodec.openResponseBody(response)).build();
}
if ("close".equalsIgnoreCase(response.request().header("Connection")) || "close".equalsIgnoreCase(response.header("Connection"))) {
streamAllocation.noNewStreams();
}
if ((code == 204 || code == 205) && response.body().contentLength() > 0L) {
throw new ProtocolException("HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
} else {
//结果没问题,返回response对象
return response;
}
}
代码有点多,简而言之就是通过HttpCodec和RealConnect这些网络访问组件读取封装到Request中的信息,然后进行网络请求,之后封装响应,通过code判断结果,结果无误,返回响应对象response。然后递归回溯,每一个拦截器都执行proceed函数下面的代码,然后把response对象返回,直到主函数。
如果大家还记得上面的代码,就会想到在第一个RealInterceptorChain对象生成时HttpCodec这些对象传入的都是空值,为什么现在就可以调用了呢?这一块是由ConnectInterceptor这个拦截器准备的,这个拦截器的目的就是为网络请求准备连接和实例化和各个组件,然后传入下一个RealInterceptorChain中,然后层层传递就到了CallServerInterceptor中了。
⑤:操作response获取信息
Response对象中封装着一个响应的所有信息,通过它的各种函数可以拿到相应的信息。
至此,我们第一个示例,阻塞请求就完美结束了。可喜可贺。在进行非阻塞请求示例解析之前先来梳理一下整个流程。
如果能理解OkHttpClient的拦截器链的处理过程,那也就理解了整个核心操作过程。
2.非阻塞方式使用OkHttpClient
其实在开发的过程中,非阻塞方式使用的更多,但是非阻塞方法要比阻塞方法麻烦一点,所以我们才要从阻塞方式开始,不过他们的核心思想都是一样的。
public static void nonblockRequest() {
String url = "http://wwww.baidu.com";
OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
//封装call
Call call = okHttpClient.newCall(request);
//非阻塞请求方式
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("error");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
System.out.println("onResponse: " + response.body().string());
}
});
System.out.println("success");
}
还是一样的访问百度,还是一样创建OkHttpClient对象,封装request对象,封装Call对象。
不过这次调用enqueue方法,而且传入一个CallBack类型的参数对象,这一块很好理解。使用阻塞方式进行操作,线程会等待方法返回才继续执行,非阻塞方法就不同了,线程调用enqueue方法后直接就继续执行了。请求可能在任意时间执行完毕,CallBack方法就是在请求完成之后用来回调提醒我们的。
直接进入enqueue方法。
public void enqueue(Callback responseCallback) {
//防止任务重复执行
synchronized(this) {
if (this.executed) {
throw new IllegalStateException("Already Executed");
}
this.executed = true;
}
//和阻塞方式一样的前置操作
this.captureCallStackTrace();
this.eventListener.callStart(this);
//调用OkHttpClient的Dispatcher对象得到enqueue方法
this.client.dispatcher().enqueue(new RealCall.AsyncCall(responseCallback));
}
核心代码还是this.client.dispatcher().enqueue(new RealCall.AsyncCall(responseCallback));
这里把Call对象封装为AsyncCall类型的对象。关于AsyncCall等下再说。
先看Dispatcher的enqueue方法吧
void enqueue(AsyncCall call) {
//加入到等待执行队列
synchronized(this) {
this.readyAsyncCalls.add(call);
}
this.promoteAndExecute();
}
两行代码,先把任务加入到等待队列,然后调用promoteAndExecute方法
private boolean promoteAndExecute() {
assert !Thread.holdsLock(this);
List<AsyncCall> executableCalls = new ArrayList();
boolean isRunning;
AsyncCall asyncCall;
synchronized(this) {
Iterator i = this.readyAsyncCalls.iterator();
while(true) {
if (i.hasNext()) {
asyncCall = (AsyncCall)i.next();
if (this.runningAsyncCalls.size() < this.maxRequests) {
if (this.runningCallsForHost(asyncCall) < this.maxRequestsPerHost) {
i.remove();
executableCalls.add(asyncCall);
this.runningAsyncCalls.add(asyncCall);
}
continue;
}
}
isRunning = this.runningCallsCount() > 0;
break;
}
}
int i = 0;
for(int size = executableCalls.size(); i < size; ++i) {
asyncCall = (AsyncCall)executableCalls.get(i);
//执行任务
asyncCall.executeOn(this.executorService());
}
return isRunning;
}
这个方法大部分的代码都做一个任务,就是把等待队列里的任务存放到执行任务队列,还有一些阈值判断等等,并解决了线程安全问题。
关注的点应该是asynCall.executeOn(this.executorService())这个方法,就是调用之前封装之后的AsynCall的方法,并传入了线程池对象。现在来看看这个类。
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
void executeOn(ExecutorService executorService) {
assert !Thread.holdsLock(RealCall.this.client.dispatcher());
boolean success = false;
try {
//向线程池添加任务
executorService.execute(this);
success = true;
} catch (RejectedExecutionException var8) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(var8);
RealCall.this.eventListener.callFailed(RealCall.this, ioException);
this.responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
RealCall.this.client.dispatcher().finished(this);
}
}
}
protected void execute() {
.......
}
}
先不看execute方法,只看executeOn方法,除去异常处理代码意外,只有一行代码,就是加入到线程池中运行。然后在finally代码块中把任务从执行队列中出队。
等等,线程池的execute方法不是只能传入类似Runnable的线程对象吗?
再看看AsynCall类,发现它继承自NamedRunnable,那么看看这个NamedRunnable类。
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(this.name);
try {
//调用抽象方法execute
this.execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
恍然大悟,原来NamedRunnable类实现了Runnable接口,再看看run方法,调用了抽象方法execute。这种把部分方法实现交给子类的设计是不是有点眼熟,当然是大名鼎鼎的模版方法模式啦。
现在回过头看看AsynCall类怎么重写execute方法的。
protected void execute() {
boolean signalledCallback = false;
RealCall.this.timeout.enter();
try {
//这个方法也太眼熟了吧
Response response = RealCall.this.getResponseWithInterceptorChain();
if (RealCall.this.retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
this.responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
this.responseCallback.onResponse(RealCall.this, response);
}
} catch (IOException var6) {
IOException e = RealCall.this.timeoutExit(var6);
if (signalledCallback) {
Platform.get().log(4, "Callback failure for " + RealCall.this.toLoggableString(), e);
} else {
RealCall.this.eventListener.callFailed(RealCall.this, e);
this.responseCallback.onFailure(RealCall.this, e);
}
} finally {
RealCall.this.client.dispatcher().finished(this);
}
}
getResponseWithInterceptorChain()。这个方法就不用多说了吧,几乎整篇博客都是围绕这个方法写的,递归调用拦截器链。
如果任务正常执行完毕,就调用CallBack的onResponse()方法,否则调用onFailure()方法。这两个方法都是可以重写的,可在这两个方法中写一些请求完毕的逻辑。
最后在finally块中执行一些清理工作。
现在,非阻塞示例也正是分析完毕,还是通过一个流程图说明一下吧
3.小结
到目前为止,OkHttp的源码分析基本就结束了,OkHttp还提供了丰富的请求方式和请求封装。例如post方式请求和上传文件或表单这样的操作,不过其底层工作原理与上述操作也是大同小异。OkHttpClient最核心的就是他的拦截器链,再搭配多个队列和线程池操作来实现非阻塞操作。
这篇博客是我写的最长的一片博客,也是我第一篇Android学习的博客。谢谢你能坚持下来看到这里,如果文中有错误的地方的还请指出。