一俘闯、okhttp簡(jiǎn)介
OKHttp是一個(gè)處理網(wǎng)絡(luò)請(qǐng)求的開(kāi)源項(xiàng)目潭苞,Android 當(dāng)前最火熱網(wǎng)絡(luò)框架,由移動(dòng)支付Square公司貢獻(xiàn)真朗,用于替代HttpUrlConnection和Apache HttpClient(android API23 6.0里已移除HttpClient)〈苏睿現(xiàn)在在Android開(kāi)發(fā)中最火的應(yīng)用最多的聯(lián)網(wǎng)框架毫無(wú)疑問(wèn)是okhttp,目前已經(jīng)大量替代了Volley蜜猾、HttpUrlConnection秀菱。
二、okhttp用法
1)導(dǎo)包:
compile 'com.squareup.okhttp3:okhttp:3.9.1'
2)通過(guò)Builder類實(shí)例化客戶端類OkhttpClient蹭睡。
private val client: OkHttpClient by lazy {
OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(60, TimeUnit.SECONDS)
.build()
}
實(shí)例化OkhttpClient時(shí)可以通過(guò)Builder類添加一系列客戶端參數(shù)衍菱。
3)通過(guò)Builder類實(shí)例化請(qǐng)求類Request,通過(guò)OkHttpClient的newCall方法執(zhí)行請(qǐng)求肩豁。
fun get(url: String, callBack: ResponseCallBack) {
var request = Request.Builder()
.url(Api.baseUrl + url)
.build()
client.newCall(request).enqueue(
object : Callback {
override fun onFailure(call: Call, e: IOException) {
callBack?.onFail(e.toString())
}
override fun onResponse(call: Call, response: Response) {
callBack?.onSuccess(response.body()!!.string())
}
}
)
}
fun post(url: String, requestParams: RequestParams, callBack: ResponseCallBack) {
var requestBody = FormBody.Builder()
requestParams.forEach {
requestBody.add(it.key, it.value.toString())
}
var request = Request.Builder()
.url(Api.baseUrl + url)
.post(requestBody.build())
.build()
client.newCall(request).enqueue(
object : Callback {
override fun onFailure(call: Call, e: IOException) {
callBack?.onFail(e.toString())
}
override fun onResponse(call: Call, response: Response) {
callBack?.onSuccess(response.body()!!.string())
}
}
)
}
實(shí)例化Request時(shí)可以通過(guò)Builder類添加一系列請(qǐng)求參數(shù)(例如Header信息)脊串,這里也不進(jìn)行詳細(xì)描述,在分析源碼時(shí)進(jìn)行具體分析清钥。
4)同步琼锋、異步請(qǐng)求。execute()執(zhí)行同步請(qǐng)求祟昭,enqueue()執(zhí)行異步請(qǐng)求缕坎,同步請(qǐng)求方法返回Response,異步請(qǐng)求通過(guò)CallBack返回Response篡悟。
三谜叹、源碼分析
1)OkHttpClient客戶端類,主要看一下各個(gè)成員變量搬葬。
final Dispatcher dispatcher;//請(qǐng)求分發(fā)器荷腊,分發(fā)執(zhí)行Request
final @Nullable Proxy proxy;//代理
final List<Protocol> protocols;//協(xié)議,管理協(xié)議版本
final List<ConnectionSpec> connectionSpecs;//傳輸層版本和連接協(xié)議
final List<Interceptor> interceptors;//攔截器
final List<Interceptor> networkInterceptors;//網(wǎng)絡(luò)攔截器
final EventListener.Factory eventListenerFactory;//請(qǐng)求監(jiān)聽(tīng)器
final ProxySelector proxySelector;//代理選擇
final CookieJar cookieJar;//cookie
final @Nullable Cache cache;//緩存
final @Nullable InternalCache internalCache;//內(nèi)部緩存
final SocketFactory socketFactory;//socket工廠
final @Nullable SSLSocketFactory sslSocketFactory;//HTTPS ssl安全套接層工廠
final @Nullable CertificateChainCleaner certificateChainCleaner;//驗(yàn)證證書(shū)
final HostnameVerifier hostnameVerifier;//確認(rèn)主機(jī)名
final CertificatePinner certificatePinner;//證書(shū)鏈
final Authenticator proxyAuthenticator;//代理身份驗(yàn)證
final Authenticator authenticator;//本地身份驗(yàn)證
final ConnectionPool connectionPool;//連接池
final Dns dns;//DNS域名解析
final boolean followSslRedirects;//安全套接層重定向
final boolean followRedirects;//本地重定向
final boolean retryOnConnectionFailure;//連接失敗重試
final int connectTimeout;//連接超時(shí)
final int readTimeout;//讀取超時(shí)
final int writeTimeout;//寫(xiě)入超時(shí)
final int pingInterval;//ping命令時(shí)間間隔
可以看到所有成員變量都是final的急凰,這樣所有的變量賦值就全部交給Builder類女仰,Builder類是OkHttpClient的靜態(tài)內(nèi)部類。可以通過(guò)builder()來(lái)完成設(shè)置疾忍,在不進(jìn)行設(shè)置情況下會(huì)使用Builder的默認(rèn)設(shè)置乔外。
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
cookieJar = CookieJar.NO_COOKIES;
socketFactory = SocketFactory.getDefault();
hostnameVerifier = OkHostnameVerifier.INSTANCE;
certificatePinner = CertificatePinner.DEFAULT;
proxyAuthenticator = Authenticator.NONE;
authenticator = Authenticator.NONE;
connectionPool = new ConnectionPool();
dns = Dns.SYSTEM;
followSslRedirects = true;
followRedirects = true;
retryOnConnectionFailure = true;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
2)Request請(qǐng)求信息類。成員變量如下:
final HttpUrl url;//請(qǐng)求url信息
final String method;//請(qǐng)求方式(post get)
final Headers headers;//請(qǐng)求header
final @Nullable RequestBody body;//請(qǐng)求Body
final Object tag;//請(qǐng)求tag
3)執(zhí)行newCall()方法創(chuàng)建Call對(duì)象锭碳,Call接口唯一實(shí)現(xiàn)類是RealCall袁稽,是執(zhí)行請(qǐng)求的真正對(duì)象。
@Override public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
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;
}
RealCall請(qǐng)求類的源碼如下:
final class RealCall implements Call {
final OkHttpClient client;
final RetryAndFollowUpInterceptor retryAndFollowUpInterceptor;//請(qǐng)求重定向攔截器
private EventListener eventListener;
final Request originalRequest;//request信息
final boolean forWebSocket;
// Guarded by this.
private boolean executed;
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
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;
}
//同步請(qǐng)求
@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);
}
}
.....
//異步請(qǐng)求
@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));
}
@Override public void cancel() {
retryAndFollowUpInterceptor.cancel();
}
@Override public synchronized boolean isExecuted() {
return executed;
}
@Override public boolean isCanceled() {
return retryAndFollowUpInterceptor.isCanceled();
}
@SuppressWarnings("CloneDoesntCallSuperClone") // We are a final type & this saves clearing state.
@Override public RealCall clone() {
return RealCall.newRealCall(client, originalRequest, forWebSocket);
}
StreamAllocation streamAllocation() {
return retryAndFollowUpInterceptor.streamAllocation();
}
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
String host() {
return originalRequest.url().host();
}
Request request() {
return originalRequest;
}
RealCall get() {
return RealCall.this;
}
@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);
}
}
}
//鏈?zhǔn)秸?qǐng)求方法
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>();
interceptors.addAll(client.interceptors());
interceptors.add(retryAndFollowUpInterceptor);
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);
}
先來(lái)分析同步請(qǐng)求擒抛,從源碼中可以看到同步請(qǐng)求中會(huì)先通過(guò)
client.dispatcher().executed(this);
完成對(duì)請(qǐng)求的監(jiān)聽(tīng)推汽,本質(zhì)上是將當(dāng)前請(qǐng)求放入一個(gè)隊(duì)列中,當(dāng)請(qǐng)求結(jié)束之后再移除隊(duì)列歧沪。
/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
對(duì)于異步請(qǐng)求來(lái)說(shuō)同樣會(huì)進(jìn)行請(qǐng)求的監(jiān)聽(tīng)歹撒,唯一的區(qū)別在于異步請(qǐng)求是用兩個(gè)隊(duì)列完成,一個(gè)是等待請(qǐng)求的隊(duì)列诊胞,一個(gè)是正在請(qǐng)求的隊(duì)列暖夭。
/** 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<>();
最終進(jìn)行網(wǎng)絡(luò)請(qǐng)求是通過(guò)鏈?zhǔn)椒椒╣etResponseWithInterceptorChain來(lái)完成的。這個(gè)方法也是網(wǎng)絡(luò)請(qǐng)求的精髓所在撵孤。這個(gè)方法里通過(guò)獲取設(shè)置的一系列攔截器來(lái)完成網(wǎng)絡(luò)請(qǐng)求工作迈着,每個(gè)攔截器有不同的分工。最后通過(guò)構(gòu)建的攔截器鏈調(diào)用proceed()方法完成網(wǎng)絡(luò)請(qǐng)求邪码。由于不同的攔截器分別負(fù)責(zé)網(wǎng)絡(luò)請(qǐng)求中的不同工作裕菠。分析起來(lái)內(nèi)容比較多,這里先不進(jìn)行具體各個(gè)攔截器的源碼分析闭专。
4)Dispatcher請(qǐng)求分發(fā)器奴潘,在okhttp中網(wǎng)絡(luò)請(qǐng)求分發(fā)是通過(guò)Dispatcher分發(fā)器來(lái)維護(hù)的,Dispatcher控制著當(dāng)前網(wǎng)絡(luò)請(qǐng)求是否執(zhí)行還是進(jìn)入等待狀態(tài)影钉,這里涉及一些網(wǎng)絡(luò)請(qǐng)求的域名等判斷信息画髓。Dispatcher類源碼如下:
public final class Dispatcher {
private int maxRequests = 64;//最大請(qǐng)求數(shù)
private int maxRequestsPerHost = 5;//最大主機(jī)名
private @Nullable Runnable idleCallback;
private @Nullable ExecutorService executorService;//請(qǐng)求線程池,核心線程0平委,非核心線程最大值Integer.MAX_VALUE
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();//異步等待隊(duì)列
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();//異步請(qǐng)求隊(duì)列
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();//同步請(qǐng)求隊(duì)列
.......
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
public synchronized void setMaxRequests(int maxRequests) {
if (maxRequests < 1) {
throw new IllegalArgumentException("max < 1: " + maxRequests);
}
this.maxRequests = maxRequests;
promoteCalls();
}
public synchronized int getMaxRequests() {
return maxRequests;
}
public synchronized void setMaxRequestsPerHost(int maxRequestsPerHost) {
if (maxRequestsPerHost < 1) {
throw new IllegalArgumentException("max < 1: " + maxRequestsPerHost);
}
this.maxRequestsPerHost = maxRequestsPerHost;
promoteCalls();
}
public synchronized int getMaxRequestsPerHost() {
return maxRequestsPerHost;
}
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
private void promoteCalls() {
if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.
if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.
for (Iterator<AsyncCall> i = readyAsyncCalls.iterator(); i.hasNext(); ) {
AsyncCall call = i.next();
if (runningCallsForHost(call) < maxRequestsPerHost) {
i.remove();
runningAsyncCalls.add(call);
executorService().execute(call);
}
if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.
}
}
private int runningCallsForHost(AsyncCall call) {
int result = 0;
for (AsyncCall c : runningAsyncCalls) {
if (c.host().equals(call.host())) result++;
}
return result;
}
synchronized void executed(RealCall call) {
runningSyncCalls.add(call);
}
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
void finished(RealCall call) {
finished(runningSyncCalls, call, false);
}
private <T> void finished(Deque<T> calls, T call, boolean promoteCalls) {
int runningCallsCount;
Runnable idleCallback;
synchronized (this) {
if (!calls.remove(call)) throw new AssertionError("Call wasn't in-flight!");
if (promoteCalls) promoteCalls();
runningCallsCount = runningCallsCount();
idleCallback = this.idleCallback;
}
if (runningCallsCount == 0 && idleCallback != null) {
idleCallback.run();
}
}
public synchronized List<Call> runningCalls() {
List<Call> result = new ArrayList<>();
result.addAll(runningSyncCalls);
for (AsyncCall asyncCall : runningAsyncCalls) {
result.add(asyncCall.get());
}
return Collections.unmodifiableList(result);
}
public synchronized int queuedCallsCount() {
return readyAsyncCalls.size();
}
public synchronized int runningCallsCount() {
return runningAsyncCalls.size() + runningSyncCalls.size();
}
}
在同步請(qǐng)求時(shí)直接加入同步請(qǐng)求隊(duì)列中奈虾,持有同步請(qǐng)求的請(qǐng)求引用。對(duì)于異步請(qǐng)求來(lái)講廉赔,會(huì)判斷當(dāng)前正在執(zhí)行的請(qǐng)求是否達(dá)到最大請(qǐng)求限制愚墓,并且正在執(zhí)行請(qǐng)求的主機(jī)名是否達(dá)到個(gè)數(shù)限制,如果都沒(méi)有達(dá)到限制昂勉,則立即通過(guò)線程池進(jìn)行網(wǎng)絡(luò)請(qǐng)求,否則放入異步等待隊(duì)列扫腺。那么什么時(shí)候進(jìn)行執(zhí)行等待隊(duì)列中的請(qǐng)求呢岗照?
在一個(gè)網(wǎng)絡(luò)請(qǐng)求結(jié)束之后會(huì)調(diào)用Dispatcher的finished方法,在finished方法中會(huì)調(diào)用promoteCalls()方法來(lái)判斷時(shí)候可以執(zhí)行等待隊(duì)列中的網(wǎng)絡(luò)請(qǐng)求。
文中demo代碼:https://github.com/24KWYL/okhttp.git