准备
okhttp官网:http://square.github.io/okhttp/
豆瓣测试接口:https://api.douban.com/v2/movie/top250?start=0&count=10
基础使用
同步方式
GET
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250?start=0&count=10").build();
Call call = mOkHttpClient.newCall(request);
try {
Response response = call.execute();
String stringResponse = response.body().string();
System.out.println("stringGetResponse ==> " + stringResponse);
} catch (IOException e) {
e.printStackTrace();
}
POST
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
RequestBody mRequestBody = new FormBody.Builder().add("start", "0").add("count", "10").build();
Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250").post(mRequestBody).build();
Call call = mOkHttpClient.newCall(request);
try {
Response response = call.execute();
String stringResponse = response.body().string();
System.out.println("stringPostResponse ==> " + stringResponse);
} catch (IOException e) {
e.printStackTrace();
}
Header
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
RequestBody mRequestBody = new FormBody.Builder().add("start", "0").add("count", "10").build();
Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250").header("token", "logintoken").post(mRequestBody).build();
System.out.println("reqstring ==> " + request.headers().toString() + "__________" +request.header("token").toString());
Call call = mOkHttpClient.newCall(request);
try {
Response response = call.execute();
String stringResponse = response.body().string();
System.out.println("stringPostResponse ==> " + stringResponse);
} catch (IOException e) {
e.printStackTrace();
}
Interceptor
/*************************************************核心代码***********************************************/
Interceptor interceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
String url = request.url().toString();
System.out.println("Interceptor url == " + url);
return chain.proceed(request);
}
};
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().addInterceptor(interceptor).addNetworkInterceptor(interceptor).build();
/*************************************************核心代码***********************************************/
Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250?start=0&count=10").build();
Call call = mOkHttpClient.newCall(request);
try {
Response response = call.execute();
String stringResponse = response.body().string();
System.out.println("stringGetResponse ==> " + stringResponse);
} catch (IOException e) {
e.printStackTrace();
}
异步方式
GET
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250?start=0&count=10").build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("stringGetResponse ==> onFailure");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String stringResponse = response.body().string();
System.out.println("stringGetResponse ==> " + stringResponse);
}
});
POST
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
RequestBody mRequestBody = new FormBody.Builder().add("start", "0").add("count", "10").build();
Request request = new Request.Builder().url("https://api.douban.com/v2/movie/top250").post(mRequestBody).build();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
System.out.println("stringPostResponse ==> onFailure" + "");
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String stringResponse = response.body().string();
System.out.println("stringPostResponse ==> " + stringResponse);
}
});
1.OkHttp中的拦截器分2个:APP层面的拦截器(Application Interception)、网络请求层面的拦截器(Network Interception)。
2.OkHttp的拦截器是在OkHttp2.2之后才可以使用,并且拦截器不能与Retrofit ≤ 1.8和Picasso ≤ 2.4框架同时使用。
3.OkHttp使用列表来跟踪拦截器,并按顺序调用拦截器。
源码解析
Dispatcher
先说一下,这个框架内有个很重要的东西叫做Dispatcher
,意为调度器,我们先看下他在哪儿定义的。
Dispatcher的初始化
OkHttpClient.java内定义的,通过builder.dispatcher对其进行赋值
OkHttpClient(Builder builder) {
......
this.dispatcher = builder.dispatcher;
......
}
OkHttpClient.builder是OkHttpClient一个静态内部类,在其构造内进行了初始化
OkHttpClient {
......
public static final class Builder {
public Builder() {
......
dispatcher = new Dispatcher();
......
}
}
}
我们一般在我们的业务类里边初始化的时候是这么new出来的。到这里相当于就初始化了这个Builder。
OkHttpClient mOkHttpClient = new OkHttpClient.Builder().build();
Dispatche初步分析
先来看看定义了些啥:
public final class Dispatcher {
private int maxRequests = 64;//最大并发请求数为64
private int maxRequestsPerHost = 5;//每个主机最大请求数为5
private @Nullable Runnable idleCallback;//执行的任务
/** Executes calls. Created lazily. */
private @Nullable ExecutorService executorService;//线程池
/** 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<>();
......
}
HttpClient到Dispatcher的切入点
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() { ...... });
抵达Call的enqueue
,而Call是个抽象类,于是进入到了RealCall
的enqueue
@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));
}
看最后一行:
client.dispatcher().enqueue(new AsyncCall(responseCallback));
再到dispatcher的enqueue
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
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;
}
- 可以看到入参为一个异步AsyncCall。
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost)
,如果运行队列内的线程数小于最大线程数,并且,主机数小于最大主机阈值,则runningAsyncCalls.add(call);
executorService().execute(call);
加入运行队列,并命令线程池去执行这几个任务。- 这里的AsyncCall是个Runnable子类,所以能被Excutor线程池执行。executorService方法是拿到一个单例线程池
executorService
。
关于请求响应的回调
final class RealCall implements Call {
......
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
AsyncCall(Callback responseCallback) {
super("OkHttp %s", redactedUrl());
this.responseCallback = responseCallback;
}
}
}
/*
* Copyright (C) 2014 Square, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package okhttp3;
import java.io.IOException;
public interface Callback {
/**
* Called when the request could not be executed due to cancellation, a connectivity problem or
* timeout. Because networks can fail during an exchange, it is possible that the remote server
* accepted the request before the failure.
*/
void onFailure(Call call, IOException e);
/**
* Called when the HTTP response was successfully returned by the remote server. The callback may
* proceed to read the response body with {@link Response#body}. The response is still live until
* its response body is {@linkplain ResponseBody closed}. The recipient of the callback may
* consume the response body on another thread.
*
* <p>Note that transport-layer success (receiving a HTTP response code, headers and body) does
* not necessarily indicate application-layer success: {@code response} may still indicate an
* unhappy HTTP response code like 404 or 500.
*/
void onResponse(Call call, Response response) throws IOException;
}
class AsyncCall{
@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);
}
}
}
关于3个Deque
/** 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<>();
前俩个泛型是AsyncCall是异步的队列,后一个泛型是RealCall的是同步的队列,这个Deque是java包中的一个接口,它是这个框架使用生产者消费者模式的一个体现。
看下它的类结构:
那么我们来看下它是怎么实现的:
dispatcher内new的3个是ArrayDeque,内部是一个数组。
/**
* Constructs an empty array deque with an initial capacity
* sufficient to hold 16 elements.
*/
public ArrayDeque() {
elements = new Object[16];
}