初始化能夠添加自定義的攔截器web
OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(interceptorImpl).builder();//建立OKHttpClient的Builder
複製代碼
基本使用緩存
String url = "http://wwww.baidu.com";
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) {
Log.d(TAG, "onFailure: ");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, "onResponse: " + response.body().string());
}
});
複製代碼
通常的使用大體就是這樣的bash
OkHttpClient.Builder()使用builder模式,用戶能夠自定義相應的參數cookie
開發通常會用到的是網絡
.connectTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.addInterceptor(interceptorImpl)
複製代碼
鏈接時間,寫時間,讀時間以及對應的Interceptor相關的攔截器多線程
Request用的也是Builder模式,好處主要是能夠動態配置相應的參數異步
Request(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers.build();
this.body = builder.body;
this.tags = Util.immutableMap(builder.tags);
}
複製代碼
tag主要是作標識的,請求返回爲null時候的標識操做socket
構建Call,主要是調用RealCall.newRealCall方法,並在其內部添加了一個事件回調監聽async
/**
* Prepares the {@code request} to be executed at some point in the future.
*/
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
//RealCall
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
// Safely publish the Call instance to the EventListener.
RealCall call = new RealCall(client, originalRequest, forWebSocket);
//添加一個事件回調,後續會有用處
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
複製代碼
而在newRealCall方法中同時也調用了RealCall的構造方法 構造方法中加入了RetryAndFollowUpInterceptor重試攔截器,okhttp中加入了不少攔截器,這也是一大特點ide
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
複製代碼
@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));
}
複製代碼
executed以及synchronized主要是用來防止重複操做和多線程同步用的
接下來的方法
private void captureCallStackTrace() {
Object callStackTrace = Platform.get().getStackTraceForCloseable("response.body().close()");
retryAndFollowUpInterceptor.setCallStackTrace(callStackTrace);
}
複製代碼
重試監聽器作一些棧StackTrace記錄,以及eventListener.callStart(this);事件監聽作回調處理,不影響流程
接着就到了Dispatcher的enqueue方法
/** Ready async calls in the order they'll be run. */ private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>(); /** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */ private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>(); synchronized void enqueue(AsyncCall call) { if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) { runningAsyncCalls.add(call); executorService().execute(call); } else { readyAsyncCalls.add(call); } } 複製代碼
Dispatcher中定義三個隊列分別是readyAsyncCalls異步等待,同步運行runningAsyncCalls以及runningSyncCalls異步運行隊列,enqueue方法中,當運行異步隊列個數小於最大請求數(64)而且同一Host請求個數小於maxRequestsPerHost(5)則加入異步運行隊列,而且用線程執行,不然加入異步等待隊列中,這是okhttp的線程隊列優化
AsyncCall 繼承了NamedRunnable,其內部會run方法會調用execute(),代碼以下
@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);
}
}
}
複製代碼
signalledCallback這個標識用來處理是否打印對應的日誌,這裏能夠看到Response類,說明網絡請求是在getResponseWithInterceptorChain中完成的,以後會回調當前的Call狀態值
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
//失敗重試攔截器
interceptors.add(retryAndFollowUpInterceptor);
//request和response攔截器
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//緩存攔截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//網絡請求鏈接攔截器
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//網絡攔截器
interceptors.addAll(client.networkInterceptors());
}
//實際網絡請求的攔截器
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,
originalRequest, this, eventListener, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
return chain.proceed(originalRequest);
}
複製代碼
加入各式各樣的攔截器,各個攔截器之間不耦合,易於用戶的本身配置,最後調用RealInterceptorChain的proceed方法
public RealInterceptorChain(List<Interceptor> interceptors, StreamAllocation streamAllocation,
HttpCodec httpCodec, RealConnection connection, int index, Request request, Call call,
EventListener eventListener, int connectTimeout, int readTimeout, int writeTimeout) {
this.interceptors = interceptors;
this.connection = connection;
this.streamAllocation = streamAllocation;
this.httpCodec = httpCodec;
this.index = index;
this.request = request;
this.call = call;
this.eventListener = eventListener;
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
RealConnection connection) throws IOException {
if (index >= interceptors.size()) throw new AssertionError();
calls++;
//...
// Call the next interceptor in the chain.
RealInterceptorChain next = new RealInterceptorChain(interceptors, streamAllocation, httpCodec,
connection, index + 1, request, call, eventListener, connectTimeout, readTimeout,
writeTimeout);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next);
// .....
return response;
}
複製代碼
構造方法中加入了eventListener事件監聽,看來okhttp中eventListener的監聽一直延伸到這裏,還加入了
this.connectTimeout = connectTimeout;
this.readTimeout = readTimeout;
this.writeTimeout = writeTimeout;
複製代碼
鏈接時間的配置
要重點關注的是index這個字段,前面傳進來的時候,默認是0,而在proceed方法中,又從新執行了RealInterceptorChain的構造方法,並經過 interceptors.get(index)獲取下一個攔截器,而且執行interceptor.intercept(next)方法,隨便找一個攔截器看看
public final class BridgeInterceptor implements Interceptor {
@Override public Response intercept(Chain chain) throws IOException {
//省略部分代碼
Response networkResponse = chain.proceed(requestBuilder.build());
//省略部分代碼
return responseBuilder.build();
}
}
複製代碼
攔截器內部又從新調用了chain.proceed的方法,這和遞歸操做相似,也是okHttp最經典的責任鏈模式。
@Override public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
eventListener.callStart(this);
try {
client.dispatcher().executed(this);
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
複製代碼
同步請求也是經過getResponseWithInterceptorChain來完成的,流程更簡單