先来看 OKhttp 的简单使用
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(DEFAULT_TIME_OUT, TimeUnit.SECONDS);//连接超时时间
builder.writeTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//写操作 超时时间
builder.readTimeout(DEFAULT_READ_TIME_OUT, TimeUnit.SECONDS);//读操作 超时时间
//日志拦截器
//注意使用这个拦截器需要增加 com.squareup.okhttp3:logging-interceptor:3.4.1 配置
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(loggingInterceptor);
OkHttpClient client = builder.build();
Request request = new Request.Builder()
.url("http://wanandroid.com/wxarticle/chapters/")
.build();
okhttp3.Call call = client.newCall(request);
call.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
Log.e("TAG", "onFailure: ---->" + e.getMessage());
}
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
Log.e("TAG", "OKhttp onResponse: ----->" + response.body().string());
}
});
先来看 OkHttpClient.Builder 做了什么
public Builder() {
dispatcher = new Dispatcher();
protocols = DEFAULT_PROTOCOLS;
connectionSpecs = DEFAULT_CONNECTION_SPECS;
eventListenerFactory = EventListener.factory(EventListener.NONE);
proxySelector = ProxySelector.getDefault();
if (proxySelector == null) {
proxySelector = new NullProxySelector();
}
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;
callTimeout = 0;
connectTimeout = 10_000;
readTimeout = 10_000;
writeTimeout = 10_000;
pingInterval = 0;
}
初始化了一大堆东西
//给 connectTimeout 重新赋值,返回本身,常见的Builder写法
public Builder connectTimeout(long timeout, TimeUnit unit) {
connectTimeout = checkDuration("timeout", timeout, unit);
return this;
}
//添加拦截器,就是往 interceptors 中添加数据
public Builder addInterceptor(Interceptor interceptor) {
if (interceptor == null) throw new IllegalArgumentException("interceptor == null");
interceptors.add(interceptor);
return this;
}
常见的一些重新设置或添加的方法
//直接 new OkHttpClient 并将自己传过去
public OkHttpClient build() {
return new OkHttpClient(this);
}
OkHttpClient(Builder builder) {
//通过Builder设置的值,赋给 OkHttpClient
this.dispatcher = builder.dispatcher;
this.proxy = builder.proxy;
this.protocols = builder.protocols;
this.connectionSpecs = builder.connectionSpecs;
this.interceptors = Util.immutableList(builder.interceptors);
this.networkInterceptors = Util.immutableList(builder.networkInterceptors);
this.eventListenerFactory = builder.eventListenerFactory;
this.proxySelector = builder.proxySelector;
this.cookieJar = builder.cookieJar;
this.cache = builder.cache;
this.internalCache = builder.internalCache;
this.socketFactory = builder.socketFactory;
//.....
}
最后通过 build 方法创建出一个 OkHttpClient 对象,很熟悉的Builder设计模式,通过Builder来构建 Client 对象。继续往下看:
Request request = new Request.Builder()
.url("http://wanandroid.com/wxarticle/chapters/")
.build();
这一段代码和 OkHttpClient.Builder 方式一样,通过 Request.Builder() 来构建 Request 对象,也是做一些保存数据检验操作。这里就不多说了,继续看:
okhttp3.Call call = client.newCall(request);
@Override public Call newCall(Request request) {
////OkHttpClient 中 所以this就是 OkHttpClient
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.transmitter = new Transmitter(client, call);
return call;
}
通过上面可以知道, okhttp3.Call 的实际对象为 RealCall ,所以后面调用的 call.enqueue 方法就是 RealCall.enqueue 方法,来看该方法:
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
//executed 默认值为false
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
//通知 EventListener 调用 callStart 方法
//应该是一个生命周期监听方法
transmitter.callStart();
//主要的是这一句
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
通过前面 OkHttpClient.Builder 可以知道 dispatcher() 返回的是 Dispatcher 对象
void enqueue(AsyncCall call) {
synchronized (this) {
//准备队列中添加该 call
//
readyAsyncCalls.add(call);
//RealCall.newRealCall(this, request, false /* for web socket */); 根据这个可以知道这个if会进来
//判断当前 host 的Call 是否已经存在
//如果存在将已经存在的 callsPerHost 赋值给当前call
// callsPerHost 也就是主机数,后面用来判断是否超过最大主机数
if (!call.get().forWebSocket) {
AsyncCall existingCall = findExistingCallWithHost(call.host());
if (existingCall != null) call.reuseCallsPerHostFrom(existingCall);
}
}
//执行
promoteAndExecute();
}
往readyAsyncCalls队列中增加当前的call,最后执行,来看执行的方法
private boolean promoteAndExecute() {
assert (!Thread.holdsLock(this));
//新建执行的Call的list
List executableCalls = new ArrayList<>();
//标志是否正在运行
boolean isRunning;
synchronized (this) {
//循环 readyAsyncCalls,也就是准备队列
for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {
//得到准备队列中的Call
AsyncCall asyncCall = i.next();
//判断正在运行的队列中的请求数是否大于最大请求数,大于则返回
//最大值为 64
if (runningAsyncCalls.size() >= maxRequests) break; // Max capacity.
//判断主机数是否大于最大主机数,大于则返回
//最大值为5
if (asyncCall.callsPerHost().get() >= maxRequestsPerHost) continue; // Host max capacity.
//如果没有返回,将当前数据从准备队列中移除
i.remove();
//将主机数加1
asyncCall.callsPerHost().incrementAndGet();
//往executableCalls 中增加当前call
executableCalls.add(asyncCall);
//运行队列中增加call
runningAsyncCalls.add(asyncCall);
}
//运行队列中存在数据,说明正在运行
isRunning = runningCallsCount() > 0;
}
//循环 executableCalls
//加入请求数和主机数都没有超出最大值,executableCalls 就会有数据,否则没有
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//执行 executeOn 方法
asyncCall.executeOn(executorService());
}
return isRunning;
}
最后会执行到 AsyncCall 的 executeOn 方法,AsyncCall 是 RealCall 的一个内部类,在 client.dispatcher().enqueue(new AsyncCall(responseCallback)); 时创建,来看 AsyncCall.executeOn 方法
void executeOn(ExecutorService executorService) {
assert (!Thread.holdsLock(client.dispatcher()));
//标记为,是否执行成功
boolean success = false;
try {
//调用线程池 execute 方法
executorService.execute(this);
success = true;
} catch (RejectedExecutionException e) {
InterruptedIOException ioException = new InterruptedIOException("executor rejected");
ioException.initCause(e);
transmitter.noMoreExchanges(ioException);
responseCallback.onFailure(RealCall.this, ioException);
} finally {
if (!success) {
client.dispatcher().finished(this); // This call is no longer running!
}
}
}
其中 executorService 是在 asyncCall.executeOn(executorService()); 时候赋值的,来看executorService() 方法
public synchronized ExecutorService executorService() {
if (executorService == null) {
executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,
new SynchronousQueue<>(), Util.threadFactory("OkHttp Dispatcher", false));
}
return executorService;
}
其实就是创建一个线程池,根据线程池可以知道 executorService.execute(this); this 是一个 实现 Runnable 接口的对象,并且调用 execute 方法后会调用 run 方法。AsyncCall 继承 NamedRunnable 去看 NamedRunnable
//实现了 Runnable 接口
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = Util.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
//为当前线程设置名称
Thread.currentThread().setName(name);
try {
//调用 execute
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
最后调用 execute 方法,execute 方法为抽象方法,又会回到AsyncCall的 execute 方法中
@Override protected void execute() {
boolean signalledCallback = false;
transmitter.timeoutEnter();
try {
//调用 getResponseWithInterceptorChain 得到请求数据
Response response = getResponseWithInterceptorChain();
signalledCallback = true;
// responseCallback 就是使用时调用call.enqueue(new okhttp3.Callback() )传过来的
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 {
//请求结束后将队列中call移除
client.dispatcher().finished(this);
}
}
最终来到 getResponseWithInterceptorChain 方法中
Response getResponseWithInterceptorChain() throws IOException {
// Build a full stack of interceptors.
List interceptors = new ArrayList<>();
//通过addInterceptor()方法添加的拦截器条件到interceptors头部
interceptors.addAll(client.interceptors());
//重试拦截器
interceptors.add(new RetryAndFollowUpInterceptor(client));
//配置请求头拦截器,配置请求头信息
interceptors.add(new BridgeInterceptor(client.cookieJar()));
//缓存拦截器
interceptors.add(new CacheInterceptor(client.internalCache()));
//初始化socket连接
interceptors.add(new ConnectInterceptor(client));
if (!forWebSocket) {
//通过addNetworkInterceptor()方法添加对的拦截器添加到获取数据之前
interceptors.addAll(client.networkInterceptors());
}
//通过前面初始化的socket,和服务器通信
interceptors.add(new CallServerInterceptor(forWebSocket));
//责任链的设计模式,不断调用拦截器,直到其中一个拦截器返回数据
Interceptor.Chain chain = new RealInterceptorChain(interceptors, transmitter, null, 0,
originalRequest, this, client.connectTimeoutMillis(),
client.readTimeoutMillis(), client.writeTimeoutMillis());
boolean calledNoMoreExchanges = false;
try {
//得到网络返回数据
Response response = chain.proceed(originalRequest);
if (transmitter.isCanceled()) {
closeQuietly(response);
throw new IOException("Canceled");
}
return response;
} catch (IOException e) {
calledNoMoreExchanges = true;
throw transmitter.noMoreExchanges(e);
} finally {
if (!calledNoMoreExchanges) {
transmitter.noMoreExchanges(null);
}
}
}
getResponseWithInterceptorChain 方法就是通过责任链的设计模式,不断循环拦截器直到又数据返回,如何请求网络得到数据,可以自行了解 CallServerInterceptor 的 intercept 方法。
其中责任链的设计模式:你想请一个月的假,你上报给了你的上级领导,你的上级领导批不了这么长的假;他也上报给他的上级领导,最后一层层的上报,直到上报到了老板,老板给你批了假,老板将结果反馈给上报给他的下属,这个下属又反馈个他的下属,一层层往下,最后到你自己这里,得到答复可以请假。如果不明白,可以将这些类拷贝到idea中,自己实现一遍
到这里,数据已经获取,通过 responseCallback 返回,responseCallback 就是调用时候传过来的
//这里的 okhttp3.Callback() 就是 responseCallback 的值
call.enqueue(new okhttp3.Callback() {
@Override
public void onFailure(okhttp3.Call call, IOException e) {
Log.e("TAG", "onFailure: ---->" + e.getMessage());
}
@Override
public void onResponse(okhttp3.Call call, okhttp3.Response response) throws IOException {
Log.e("TAG", "OKhttp onResponse: ----->" + response.body().string());
}
});
最后得到数据,因为使用了线程池,所以 onResponse 是在异步线程中的
完
OKhttp 主要使用了Builder模式和责任链模式,只要掌握了这两种模式,那么 OKhttp 就不是很难的东西。