1.okhttp的具體用法
首先需要在gradle文件中添加依賴(lài)惧眠,一個(gè)是OkHttp庫(kù)疹瘦,一個(gè)是Okio庫(kù)霜定,后者是前者通信的基礎(chǔ)。首先我們先看一下OkHttp的具體用法.
1).get請(qǐng)求
OkHttpClient client =new OkHttpClient();
Request request =new Request.Builder()
.url("這里是請(qǐng)求的鏈接")
.build();
Response response =client.newCall(request).execute();
String responseData =response.body().string();
首先需要?jiǎng)?chuàng)建一個(gè)OkHttpClient 對(duì)象思喊,如果需要發(fā)送http請(qǐng)求奔誓,還需要?jiǎng)?chuàng)建一個(gè)Request對(duì)象,在build()之前有很多連綴方法來(lái)豐富Request對(duì)象搔涝,在這里我們只用了url()傳入了目標(biāo)網(wǎng)絡(luò)地址。然后使用OkHttpClient 的newCall()方法來(lái)創(chuàng)建一個(gè)Call對(duì)象和措,并且調(diào)用它的execute()方法來(lái)發(fā)送請(qǐng)求并且獲取數(shù)據(jù)庄呈,Response對(duì)象就是服務(wù)器返回的數(shù)據(jù)。這里的execute()方法是同步請(qǐng)求方法派阱,如果需要使用異步請(qǐng)求需要使用Call對(duì)象的enqueue()方法 诬留,并且配合Handler進(jìn)行回調(diào)使用,實(shí)際中使用異步請(qǐng)求的情況也比較多。
2).post請(qǐng)求
ResponseBody responseBody =new FormBody.Builder()
.add("鍵","值")
.build();
Request request =new Request.Builder()
.url("這里是請(qǐng)求的鏈接")
.post(responseBody)
.build();
post請(qǐng)求稍微比get請(qǐng)求復(fù)雜一點(diǎn)文兑,主要是要在ResponseBody 中添加需要傳入的參數(shù)盒刚,其余的操作就和get請(qǐng)求一樣了。
2.okhttp的請(qǐng)求過(guò)程
1.)從請(qǐng)求開(kāi)始分析
當(dāng)我們?cè)L問(wèn)網(wǎng)絡(luò)的是時(shí)候需要newOkHttpClient.newCall(request)的execute()或者enqueue()方法绿贞。當(dāng)我們調(diào)用newCall()因块,實(shí)際上是返回的一個(gè)RealCall對(duì)象,實(shí)際上調(diào)用的enqueue()和execute()也是RealCall的方法籍铁。
@Override
public Call newCall(Request request){
return new RealCall(this, request);
}
void enqueue(Callback response Callback, boolean forWebSocket){
synchronized(this) {
if(executed) throw new IllegalStateException("Already Executed");
executed =true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
可以看到最終的請(qǐng)求是dispatcher來(lái)完成的涡上。這里面最重要的就是enqueue()方法。
2)Dispatcher調(diào)度器
Dispacther主要用于控制并發(fā)的請(qǐng)求拒名,主要維護(hù)的變量如下
/** 最大并發(fā)請(qǐng)求數(shù)*/
private int maxRequests = 64;
/** 每個(gè)主機(jī)最大請(qǐng)求數(shù)*/
private int maxRequestsPerHost = 5;
/** 消費(fèi)者線(xiàn)程池 */
private ExecutorService executorService;
/** 將要運(yùn)行的異步請(qǐng)求隊(duì)列 */
private final Deque<AsyncCall> readyAsyncCalls = new ArrayDeque<>();
/**正在運(yùn)行的異步請(qǐng)求隊(duì)列 */
private final Deque<AsyncCall> runningAsyncCalls = new ArrayDeque<>();
/** 正在運(yùn)行的同步請(qǐng)求隊(duì)列 */
private final Deque<RealCall> runningSyncCalls = new ArrayDeque<>();
public Dispatcher(ExecutorService executorService) {
this.executorService = executorService;
}
public Dispatcher() {
}
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;
}
Dispatcher有兩個(gè)構(gòu)造函數(shù)吩愧,可以使用自己設(shè)定的線(xiàn)程池,如果線(xiàn)程池為null的時(shí)候增显,在網(wǎng)絡(luò)請(qǐng)求前會(huì)自己創(chuàng)建一個(gè)線(xiàn)程池雁佳,這個(gè)線(xiàn)程池適合處理耗時(shí)比較少的任務(wù),因?yàn)槿蝿?wù)處理速度大于任務(wù)提交速度可以避免新的線(xiàn)程的創(chuàng)建同云,以免內(nèi)存被占滿(mǎn)糖权。
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
在調(diào)度器中,當(dāng)異步請(qǐng)求隊(duì)列中的數(shù)量小于最大請(qǐng)求數(shù)并且正運(yùn)行的主機(jī)數(shù)小于5時(shí)梢杭,則把請(qǐng)求加入線(xiàn)程池中温兼,并且執(zhí)行,否則就只是加入線(xiàn)程池武契,進(jìn)行等待募判。
AsyncCall
傳入線(xiàn)程池的AsyncCall 對(duì)象時(shí)RealCall的內(nèi)部類(lèi),他也實(shí)現(xiàn)了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 {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
在第四行中運(yùn)行了getResponseWithInterceptorChain()方法届垫,他返回了一個(gè)Response類(lèi)型的參數(shù),即是在這里向服務(wù)器發(fā)起請(qǐng)求的全释,因?yàn)樵O(shè)計(jì)到攔截器装处,這里不做討論。最終finally中代碼最后始終會(huì)運(yùn)行浸船,finished()方法如下妄迁。
void finished(AsyncCall call) {
finished(runningAsyncCalls, call, true);
}
...
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();
}
}
在第五行中,從隊(duì)列中移除了Call實(shí)例李命,第六行中因?yàn)閭魅氲膮?shù)promoteCalls為真登淘,所以會(huì)執(zhí)行 promoteCalls()方法
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.
}
}
promoteCalls主要作用就是從readyAsyncCalls線(xiàn)程池中獲取下一個(gè)請(qǐng)求,并且放在了runningAsyncCalls線(xiàn)程池中封字,并且調(diào)用了execute()方法處理黔州。
如何進(jìn)行網(wǎng)絡(luò)請(qǐng)求
上文說(shuō)到AsyncCall對(duì)象的execute()中運(yùn)行了getResponseWithInterceptorChain()方法耍鬓,進(jìn)行了網(wǎng)絡(luò)請(qǐng)求。
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List<Interceptor> interceptors = new ArrayList<>(); //這是一個(gè)List流妻,是有序的
interceptors.addAll(client.interceptors());//首先添加的是用戶(hù)添加的全局?jǐn)r截器
interceptors.add(retryAndFollowUpInterceptor); //錯(cuò)誤牲蜀、重定向攔截器
//橋接攔截器,橋接應(yīng)用層與網(wǎng)絡(luò)層绅这,添加必要的頭涣达、
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//緩存處理,Last-Modified君躺、ETag峭判、DiskLruCache等
interceptors.add(new CacheInterceptor(client.internalCache()));
//連接攔截器
interceptors.add(new ConnectInterceptor(client));
//從這就知道,通過(guò)okHttpClient.Builder#addNetworkInterceptor()傳進(jìn)來(lái)的攔截器只對(duì)非網(wǎng)頁(yè)的請(qǐng)求生效
if (!forWebSocket) {
interceptors.addAll(client.networkInterceptors());
}
//真正訪(fǎng)問(wèn)服務(wù)器的攔截器
interceptors.add(new CallServerInterceptor(forWebSocket));
Interceptor.Chain chain = new RealInterceptorChain(
interceptors, null, null, null, 0, originalRequest);
return chain.proceed(originalRequest);
}
這里創(chuàng)建一個(gè)關(guān)于攔截器的集合棕叫,首先將前面的client.interceptors()全部加入其中林螃,在還有創(chuàng)建 RealCall時(shí)的retryAndFollowUpInterceptor加入其中,接著還創(chuàng)建并添加了BridgeInterceptor俺泣、CacheInterceptor疗认、ConnectInterceptor、CallServerInterceptor伏钠,通過(guò)求最后RealInterceptorChain的proceed(Request)來(lái)執(zhí)行整個(gè)interceptor chain横漏,可見(jiàn)把這個(gè)攔截器鏈搞清楚,整體流程也就明朗了熟掂。這里我們只看CallServerInterceptor攔截器的功能缎浇,因?yàn)樗鼤r(shí)主要向服務(wù)器發(fā)送請(qǐng)求的攔截器。
@Override public Response intercept(Chain chain) throws IOException {
HttpCodec httpCodec = ((RealInterceptorChain) chain).httpStream();
StreamAllocation streamAllocation = ((RealInterceptorChain) chain).streamAllocation();
Request request = chain.request();
long sentRequestMillis = System.currentTimeMillis();
httpCodec.writeRequestHeaders(request);
if (HttpMethod.permitsRequestBody(request.method()) && request.body() != null) {
Sink requestBodyOut = httpCodec.createRequestBody(request, request.body().contentLength());
BufferedSink bufferedRequestBody = Okio.buffer(requestBodyOut);
request.body().writeTo(bufferedRequestBody);
bufferedRequestBody.close();
}
httpCodec.finishRequest();
Response response = httpCodec.readResponseHeaders()
.request(request)
.handshake(streamAllocation.connection().handshake())
.sentRequestAtMillis(sentRequestMillis)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
int code = response.code();
if (forWebSocket && code == 101) {
// Connection is upgrading, but we need to ensure interceptors see a non-null response body.
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() > 0) {
throw new ProtocolException(
"HTTP " + code + " had non-zero Content-Length: " + response.body().contentLength());
}
return response;
}
這部分就是從服務(wù)器發(fā)起請(qǐng)求的源碼赴肚,最終返回Response素跺,然而這里只是介紹了okhttp的如何請(qǐng)求,其實(shí)攔截器鏈才是整個(gè)框架的精髓誉券。
這里我們總結(jié)一下okhttp的請(qǐng)求過(guò)程:
newOkHttpClient.newCall(request).enqueue()方法
1.首先通過(guò)OkHttpClient創(chuàng)建一個(gè)Call對(duì)象指厌,實(shí)際上是一個(gè)RealCall
2.然后調(diào)用enqueue()方法,最終是調(diào)用client.dispatcher().enqueue()方法踊跟,主要是實(shí)現(xiàn)對(duì)任務(wù)的調(diào)度
3.最終通過(guò)攔截器實(shí)現(xiàn)對(duì)網(wǎng)絡(luò)的請(qǐng)求