說一下我個人的想法啊,很多人覺得看源碼特別難,無從下手,很多源碼看不懂。我覺得這是很正常的事,除非某個框架代碼是你寫的,不然,你很難把每一句代碼都搞懂,就連框架的作者,時間一久,都沒有辦法保證說每一句代碼都能夠看得懂。我們花個三四天,一兩個星期,都很難把我們自己公司新接手的項目熟悉完,更何況是這些框架了。我說一下我平時是怎麼看框架源碼的吧,每一個框架,首先,會用,這是最基本的,連用都不會用,還別談其他的了。其次,每一個框架,基本上都會有流程圖,這些流程圖,在網上都有。我們找到這個流程圖,這個流程圖,基本上都是整個框架的主幹,我們順着這個主幹閱讀,你就會發現,很明瞭,很清晰。當你把主體熟悉完以後,如果,你想更加深入的瞭解,你就可以在這個主體基礎上慢慢的延伸出去。好了,廢話不多說了,今天我們來了解一下OkHttp,這裏是基於OkHttp3的源碼,OkHttp2.x的源碼和OkHttp3的會有點區別。我們按照上面的說的方式來閱讀一下。
OkHttp流程圖
OkHttp基本使用
gradle依賴
1 implementation 'com.squareup.okhttp3:okhttp:3.11.0'
2 implementation 'com.squareup.okio:okio:1.15.0'
1 /**
2 *這裏拿get請求來
3 * 異步的get請求
4 */
5 public void okhttpAsyn() {
6 //設置超時的時間
7 OkHttpClient.Builder builder = new OkHttpClient.Builder()
8 .connectTimeout(15, TimeUnit.SECONDS)
9 .writeTimeout(20, TimeUnit.SECONDS)
10 .readTimeout(20, TimeUnit.SECONDS)
11 ;
12 OkHttpClient okHttpClient = builder.build();
13 Request request = new Request.Builder()
14 .get() //設置請求模式
15 .url("https://www.baidu.com/")
16 .build();
17
18 Call call = okHttpClient.newCall(request);
19 call.enqueue(new Callback() {
20 @Override
21 public void onFailure(Call call, IOException e) {
22 Log.d("MainActivity", "-----------onFailure-----------");
23 }
24
25 @Override
26 public void onResponse(Call call, Response response) throws IOException {
27 Log.d("MainActivity", "----onResponse----" + response.body().toString());
28 runOnUiThread(new Runnable() {
29 @Override
30 public void run() {
31 Toast.makeText(MainActivity.this, "請求成功", Toast.LENGTH_LONG).show();
32 }
33 });
34
35 }
36 });
37 }
OkHttp源碼分析
從OkHttp的基本使用中,我們看到,通過okHttpClient.newCall()方法,拿到這個call對象,我們看看newCall是怎麼走的
1 /**
2 * Prepares the {@code request} to be executed at some point in the future.
3 */
4 @Override public Call newCall(Request request) {
5 return RealCall.newRealCall(this, request, false /* for web socket */);
6 }
7
8
9 static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
10 // Safely publish the Call instance to the EventListener.
11 RealCall call = new RealCall(client, originalRequest, forWebSocket);
12 call.eventListener = client.eventListenerFactory().create(call);
13 return call;
14 }
從這裏的源碼知道,okHttpClient.newCall()實際上返回的是RealCall對象,而call.enqueue(),實際上是調用的了RealCall中的enqueue()方法,我們看看enqueue()方法方法怎麼走。
1 @Override public void enqueue(Callback responseCallback) {
2 synchronized (this) {
3 if (executed) throw new IllegalStateException("Already Executed");
4 executed = true;
5 }
6 captureCallStackTrace();
7 eventListener.callStart(this);
8 client.dispatcher().enqueue(new AsyncCall(responseCallback));
9 }
可以看到client.dispatcher().enqueue(new AsyncCall(responseCallback));這句代碼,也就是說,最終是有的請求是有dispatcher來完成,我們看看dispatcher。
1 /*
2 * Copyright (C) 2013 Square, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package okhttp3;
17
18 import java.util.ArrayDeque;
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.Deque;
22 import java.util.Iterator;
23 import java.util.List;
24 import java.util.concurrent.ExecutorService;
25 import java.util.concurrent.SynchronousQueue;
26 import java.util.concurrent.ThreadPoolExecutor;
27 import java.util.concurrent.TimeUnit;
28 import javax.annotation.Nullable;
29 import okhttp3.RealCall.AsyncCall;
30 import okhttp3.internal.Util;
31
32 /**
33 * Policy on when async requests are executed.
34 *
35 * <p>Each dispatcher uses an {@link ExecutorService} to run calls internally. If you supply your
36 * own executor, it should be able to run {@linkplain #getMaxRequests the configured maximum} number
37 * of calls concurrently.
38 */
39 public final class Dispatcher {
40 //最大請求的併發數
41 private int maxRequests = 64;
42 //每個主機最大請求數
43 private int maxRequestsPerHost = 5;
44 private @Nullable Runnable idleCallback;
45
46 /** 消費線程池 */
47 private @Nullable ExecutorService executorService;
48
49 /** 準備運行的異步請求隊列 */
50 private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
51
52 /** 正在運行的異步請求隊列 */
53 private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
54
55 /** 正在運行的同步請求隊列 */
56 private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
57
58 /** 構造方法 */
59 public Dispatcher(ExecutorService executorService) {
60 this.executorService = executorService;
61 }
62
63 public Dispatcher() {
64 }
65
66 public synchronized ExecutorService executorService() {
67 if (executorService == null) {
68 executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
69 new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
70 }
71 return executorService;
72 }
73
74
75
76
77 /**
78 *
79 *設置併發執行最大的請求數量
80 * <p>If more than {@code maxRequests} requests are in flight when this is invoked, those requests
81 * will remain in flight.
82 */
83 public synchronized void setMaxRequests(int maxRequests) {
84 if (maxRequests < 1) {
85 throw new IllegalArgumentException("max < 1: " + maxRequests);
86 }
87 this.maxRequests = maxRequests;
88 promoteCalls();
89 }
90
91 //獲取到最大請求的數量
92 public synchronized int getMaxRequests() {
93 return maxRequests;
94 }
95
96 /**
97 * 設置每個主機併發執行的請求的最大數量
98 * <p>If more than {@code maxRequestsPerHost} requests are in flight when this is invoked, those
99 * requests will remain in flight.
100 *
101 * <p>WebSocket connections to hosts <b>do not</b> count against this limit.
102 */
103 public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
104 if (maxRequestsPerHost < 1) {
105 throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
106 }
107 this.maxRequestsPerHost = maxRequestsPerHost;
108 promoteCalls();
109 }
110
111 //獲取每個主機最大併發數量
112 public synchronized int getMaxRequestsPerHost() {
113 return maxRequestsPerHost;
114 }
115
116 /**
117 * Set a callback to be invoked each time the dispatcher becomes idle (when the number of running
118 * calls returns to zero).
119 *
120 * <p>Note: The time at which a {@linkplain Call call} is considered idle is different depending
121 * on whether it was run {@linkplain Call#enqueue(Callback) asynchronously} or
122 * {@linkplain Call#execute() synchronously}. Asynchronous calls become idle after the
123 * {@link Callback#onResponse onResponse} or {@link Callback#onFailure onFailure} callback has
124 * returned. Synchronous calls become idle once {@link Call#execute() execute()} returns. This
125 * means that if you are doing synchronous calls the network layer will not truly be idle until
126 * every returned {@link Response} has been closed.
127 */
128 public synchronized void setIdleCallback(@Nullable Runnable idleCallback) {
129 this.idleCallback = idleCallback;
130 }
131
132 synchronized void enqueue(AsyncCall call) {
133 if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
134 runningAsyncCalls.add(call);
135 executorService().execute(call);
136 } else {
137 readyAsyncCalls.add(call);
138 }
139 }
140
141 /**
142 * Cancel all calls currently enqueued or executing. Includes calls executed both {@linkplain
143 * Call#execute() synchronously} and {@linkplain Call#enqueue asynchronously}.
144 */
145 public synchronized void cancelAll() {
146 for (AsyncCall call : readyAsyncCalls) {
147 call.get().cancel();
148 }
149
150 for (AsyncCall call : runningAsyncCalls) {
151 call.get().cancel();
152 }
153
154 for (RealCall call : runningSyncCalls) {
155 call.cancel();
156 }
157 }
158
159 private void promoteCalls() {
160 if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
161 if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
162
163 for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
164 AsyncCall call = i.next();
165
166 if (runningCallsForHost(call) < maxRequestsPerHost) {
167 i.remove();
168 runningAsyncCalls.add(call);
169 executorService().execute(call);
170 }
171
172 if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
173 }
174 }
175
176 //----------------省略若干代碼-----------------------
177
178 }
我們來找到這段代碼
1 synchronized void enqueue(AsyncCall call) {
2 if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
3 runningAsyncCalls.add(call);
4 executorService().execute(call);
5 } else {
6 readyAsyncCalls.add(call);
7 }
8 }
當正在運行的異步請求隊列中的數量小於64並且正在運行的請求主機數小於5時則把請求加載到runningAsyncCalls中並在線程池中執行,否則就再入到readyAsyncCalls中進行緩存等待。而runningAsyncCalls這個請求隊列存放的就是AsyncCall對象,而這個AsyncCall就是RealCall的內部類,也就是說executorService().execute(call);實際上走的是RealCall類中的execute()方法.
1 @Override protected void execute() {
2 boolean signalledCallback = false;
3 try {
4 Response response = getResponseWithInterceptorChain();
5 if (retryAndFollowUpInterceptor.isCanceled()) {
6 signalledCallback = true;
7 responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
8 } else {
9 signalledCallback = true;
10 responseCallback.onResponse(RealCall.this, response);
11 }
12 } catch (IOException e) {
13 if (signalledCallback) {
14 // Do not signal the callback twice!
15 Platform.get().log(INFO, "Callback failure for " + toLoggableString(), e);
16 } else {
17 eventListener.callFailed(RealCall.this, e);
18 responseCallback.onFailure(RealCall.this, e);
19 }
20 } finally {
21 client.dispatcher().finished(this);
22 }
23 }
這部分的代碼,相信很多人都能夠看的明白,無非就是一些成功,失敗的回調,這段代碼,最重要的是esponse response = getResponseWithInterceptorChain();和client.dispatcher().finished(this);我們先來看看client.dispatcher().finished(this);這句代碼是怎麼執行的。
1 /** Used by {@code AsyncCall#run} to signal completion. */
2 void finished(AsyncCall call) {
3 finished(runningAsyncCalls, call, true);
4 }
5
6 /** Used by {@code Call#execute} to signal completion. */
7 void finished(RealCall call) {
8 finished(runningSyncCalls, call, false);
9 }
10
11 private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
12 int runningCallsCount;
13 Runnable idleCallback;
14 synchronized (this) {
15 if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
16 if (promoteCalls) promoteCalls();
17 runningCallsCount = runningCallsCount();
18 idleCallback = this.idleCallback;
19 }
20
21 if (runningCallsCount == 0 && idleCallback != null) {
22 idleCallback.run();
23 }
24 }
25
26 private void promoteCalls() {
27 if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
28 if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
29
30 for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
31 AsyncCall call = i.next();
32
33 if (runningCallsForHost(call) < maxRequestsPerHost) {
34 i.remove();
35 runningAsyncCalls.add(call);
36 executorService().execute(call);
37 }
38
39 if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
40 }
41 }
由於client.dispatcher().finished(this);這句代碼是放到finally中執行的,所以無論什麼情況,都會執行上面的promoteCalls()方法,而從promoteCalls()方法中可以看出通過遍歷來獲取到下一個請求從而執行下一個網絡請求。
回過頭來,我們看看這一句代碼Response response = getResponseWithInterceptorChain(); 通過getResponseWithInterceptorChain();來獲取到response,然後回調返回。很明顯getResponseWithInterceptorChain()這句代碼裏面進行了網絡請求。我們看看是怎麼執行的。
1 Response getResponseWithInterceptorChain() throws IOException {
2 // Build a full stack of interceptors.
3 List<Interceptor> interceptors = new ArrayList<>();
4 interceptors.addAll(client.interceptors());
5 interceptors.add(retryAndFollowUpInterceptor);
6 interceptors.add(new BridgeInterceptor(client.cookieJar()));
7 interceptors.add(new CacheInterceptor(client.internalCache()));
8 interceptors.add(new ConnectInterceptor(client));
9 if (!forWebSocket) {
10 interceptors.addAll(client.networkInterceptors());
11 }
12 interceptors.add(new CallServerInterceptor(forWebSocket));
13
14 Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
15 originalRequest, this, eventListener, client.connectTimeoutMillis(),
16 client.readTimeoutMillis(), client.writeTimeoutMillis());
17
18 return chain.proceed(originalRequest);
19 }
20 }
從上面代碼可以知道,緩存,網絡請求,都封裝成攔截器的形式。攔截器主要用來觀察,修改以及可能短路的請求輸出和響應的回來。最後return chain.proceed,而chain是通過new RealInterceptorChain來獲取到的,我們來看看RealInterceptorChain對象,然後找到proceed()方法。
1 public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
2 RealConnection connection) throws IOException {
3 if (index >= interceptors.size()) throw new AssertionError();
4
5 calls++;
6
7 // If we already have a stream, confirm that the incoming request will use it.
8 if (this.httpCodec != null && !this.connection.supportsUrl(request.url())) {
9 throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
10 + " must retain the same host and port");
11 }
12
13 // If we already have a stream, confirm that this is the only call to chain.proceed().
14 if (this.httpCodec != null && calls > 1) {
15 throw new IllegalStateException("network interceptor " + interceptors.get(index - 1)
16 + " must call proceed() exactly once");
17 }
18
19 // 調用下一個攔截器
20 RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
21 connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
22 writeTimeout);
23 Interceptor interceptor = interceptors.get(index);
24 Response response = interceptor.intercept(next); //調用攔截器中的intercept()方法
25
26 // Confirm that the next interceptor made its required call to chain.proceed().
27 if (httpCodec != null && index + 1 < interceptors.size() && next.calls != 1) {
28 throw new IllegalStateException("network interceptor " + interceptor
29 + " must call proceed() exactly once");
30 }
31
32 // Confirm that the intercepted response isn't null.
33 if (response == null) {
34 throw new NullPointerException("interceptor " + interceptor + " returned null");
35 }
36
37 if (response.body() == null) {
38 throw new IllegalStateException(
39 "interceptor " + interceptor + " returned a response with no body");
40 }
41
42 return response;
43 }
從上面的代碼可以看出來,chain.proceed主要是講集合中的攔截器遍歷出來,然後通過調用每一個攔截器中的intercept()方法,然後獲取到response結果,返回。
我們看看CacheInterceptor這個類,找到intercept()方法。
1 @Override public Response intercept(Chain chain) throws IOException {
2 Response cacheCandidate = cache != null
3 ? cache.get(chain.request())
4 : null;
5
6 long now = System.currentTimeMillis();
7
8 //創建CacheStrategy.Factory對象,進行緩存配置
9 CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();
10 //網絡請求
11 Request networkRequest = strategy.networkRequest;
12 //緩存響應
13 Response cacheResponse = strategy.cacheResponse;
14
15 if (cache != null) {
16 //記錄當前請求是網絡發起還是緩存發起
17 cache.trackResponse(strategy);
18 }
19
20 if (cacheCandidate != null && cacheResponse == null) {
21 closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
22 }
23
24 // 不進行網絡請求並且緩存不存在或者過期則返回504錯誤
25 if (networkRequest == null && cacheResponse == null) {
26 return new Response.Builder()
27 .request(chain.request())
28 .protocol(Protocol.HTTP_1_1)
29 .code(504)
30 .message("Unsatisfiable Request (only-if-cached)")
31 .body(Util.EMPTY_RESPONSE)
32 .sentRequestAtMillis(-1L)
33 .receivedResponseAtMillis(System.currentTimeMillis())
34 .build();
35 }
36
37 // 不進行網絡請求,而且緩存可以使用,直接返回緩存
38 if (networkRequest == null) {
39 return cacheResponse.newBuilder()
40 .cacheResponse(stripBody(cacheResponse))
41 .build();
42 }
43
44 //進行網絡請求
45 Response networkResponse = null;
46 try {
47 networkResponse = chain.proceed(networkRequest);
48 } finally {
49 // If we're crashing on I/O or otherwise, don't leak the cache body.
50 if (networkResponse == null && cacheCandidate != null) {
51 closeQuietly(cacheCandidate.body());
52 }
53 }
54
55 //---------省略若干代碼-------------
56
57 return response;
58 }
上面我做了很多註釋,基本的流程是有緩存就取緩存裏面的,沒有緩存就請求網絡。我們來看看網絡請求的類CallServerInterceptor
1 /*
2 * Copyright (C) 2016 Square, Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 package okhttp3.internal.http;
17
18 import java.io.IOException;
19 import java.net.ProtocolException;
20 import okhttp3.Interceptor;
21 import okhttp3.Request;
22 import okhttp3.Response;
23 import okhttp3.internal.Util;
24 import okhttp3.internal.connection.RealConnection;
25 import okhttp3.internal.connection.StreamAllocation;
26 import okio.Buffer;
27 import okio.BufferedSink;
28 import okio.ForwardingSink;
29 import okio.Okio;
30 import okio.Sink;
31
32 /** This is the last interceptor in the chain. It makes a network call to the server. */
33 public final class CallServerInterceptor implements Interceptor {
34 private final boolean forWebSocket;
35
36 public CallServerInterceptor(boolean forWebSocket) {
37 this.forWebSocket = forWebSocket;
38 }
39
40 @Override public Response intercept(Chain chain) throws IOException {
41 RealInterceptorChain realChain = (RealInterceptorChain) chain;
42 HttpCodec httpCodec = realChain.httpStream();
43 StreamAllocation streamAllocation = realChain.streamAllocation();
44 RealConnection connection = (RealConnection) realChain.connection();
45 Request request = realChain.request();
46
47 long sentRequestMillis = System.currentTimeMillis();
48
49 realChain.eventListener().requestHeadersStart(realChain.call());
50 httpCodec.writeRequestHeaders(request);
51 realChain.eventListener().requestHeadersEnd(realChain.call(), request);
52
53 Response.Builder responseBuilder = null;
54 if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
55 // If there's a "Expect: 100-continue" header on the request, wait for a "HTTP/1.1 100
56 // Continue" response before transmitting the request body. If we don't get that, return
57 // what we did get (such as a 4xx response) without ever transmitting the request body.
58 if ("100-continue".equalsIgnoreCase(request.header("Expect"))) {
59 httpCodec.flushRequest();
60 realChain.eventListener().responseHeadersStart(realChain.call());
61 responseBuilder = httpCodec.readResponseHeaders(true);
62 }
63
64 if (responseBuilder == null) {
65 // Write the request body if the "Expect: 100-continue" expectation was met.
66 realChain.eventListener().requestBodyStart(realChain.call());
67 long contentLength = request.body().contentLength();
68 CountingSink requestBodyOut =
69 new CountingSink(httpCodec.createRequestBody(request, contentLength));
70 BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
71
72 request.body().writeTo(bufferedRequestBody);
73 bufferedRequestBody.close();
74 realChain.eventListener()
75 .requestBodyEnd(realChain.call(), requestBodyOut.successfulCount);
76 } else if (!connection.isMultiplexed()) {
77 // If the "Expect: 100-continue" expectation wasn't met, prevent the HTTP/1 connection
78 // from being reused. Otherwise we're still obligated to transmit the request body to
79 // leave the connection in a consistent state.
80 streamAllocation.noNewStreams();
81 }
82 }
83
84 httpCodec.finishRequest();
85
86 if (responseBuilder == null) {
87 realChain.eventListener().responseHeadersStart(realChain.call());
88 responseBuilder = httpCodec.readResponseHeaders(false);
89 }
90
91 Response response = responseBuilder
92 .request(request)
93 .handshake(streamAllocation.connection().handshake())
94 .sentRequestAtMillis(sentRequestMillis)
95 .receivedResponseAtMillis(System.currentTimeMillis())
96 .build();
97
98 int code = response.code();
99 if (code == 100) {
100 // server sent a 100-continue even though we did not request one.
101 // try again to read the actual response
102 responseBuilder = httpCodec.readResponseHeaders(false);
103
104 response = responseBuilder
105 .request(request)
106 .handshake(streamAllocation.connection().handshake())
107 .sentRequestAtMillis(sentRequestMillis)
108 .receivedResponseAtMillis(System.currentTimeMillis())
109 .build();
110
111 code = response.code();
112 }
113
114 realChain.eventListener()
115 .responseHeadersEnd(realChain.call(), response);
116
117 if (forWebSocket && code == 101) {
118 // Connection is upgrading, but we need to ensure interceptors see a non-null response body.
119 response = response.newBuilder()
120 .body(Util.EMPTY_RESPONSE)
121 .build();
122 } else {
123 response = response.newBuilder()
124 .body(httpCodec.openResponseBody(response))
125 .build();
126 }
127
128 if ("close".equalsIgnoreCase(response.request().header("Connection"))
129 || "close".equalsIgnoreCase(response.header("Connection"))) {
130 streamAllocation.noNewStreams();
131 }
132
133 if ((code == 204 || code == 205) && response.body().contentLength() > 0) {
134 throw new ProtocolException(
135 "HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
136 }
137
138 return response;
139 }
140 }
到這裏,基本上okhttp的整個流程就出來了,當然,這裏只是一個整體的大概流程,如果要摳的很細,那就不是一篇文章能夠說明的了了........現在回過頭來再看一眼流程圖,是不是感覺特別明朗了。