文章目录
1、Okhttp基本介绍
github地址:https://github.com/square/okhttp
Okhttp具有一些高效的属性:
- 在HTTP/2支持下,如果网络请求的host是同一个时,允许这些请求公用一个socket。
- 使用连接池减少网络延时(如果HTTP/2不可用)
- 透明的GZIP压缩,较少数据流量
- 缓存网络响应,避免重复网络请求
2、OkHttp的基本使用
2-1、同步请求
Request request = new Request.Builder().get().url(url).build();
OkHttpClient okHttpClient = new OkHttpClient();
try {
Response response = okHttpClient.newCall(request).execute();
Log.e("info", "==>" + response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
2-2、异步调用
okHttpClient.newCall(request).enqueue(Callback callback);
不管是同步调用还是异步调用,response.body().string()
方法只调用一次,连续调用会抛出异常。因为string()
方法在获取数据的同时,会清空buffer并关闭数据流。
- Post表单提交
表单提交主要是请求使用的Request对象是需要使用RequestBody
对象封装请求实体。然后在使用Request
的post()
方法进行参数的封装传入。
RequestBody requestBody = new FormRequest.Builder().add("", "").build();
Request request = new Request.Builder().get().url(url).post(requestBody).build();
Response response = okHttpClient.newCall(request).execute();
2-3、缓存
Cache cache = new Cache(cacheDirectory, cacheSize)
Response response = okHttpClient.newCall(request).cache(cache).execute();
2-4、拦截器
拦截器主要分为两种:一种是应用拦截器,主要拦截应用层与okhttp之间的网络请求和响应。另一种是网络拦截器,拦截okhttp与网络层之间的网络请求和响应。
3、OkHttp源码分析
3-1、okhttpClient创建
public OkHttpClient() {
this(new Builder());
}
而在Builder
中初始化了使用到的参数,比如dispatcher
、interceptors
、networkInterceptors
以及其它等配置参数。之后调用build()
方法创建OkHttpClient
对象
public OkHttpClient build() {
return new OkHttpClient(this);
}
3-2、call对象创建
Call call = client.newCall(request);
...
public Call newCall(Request request) {
return RealCall.newRealCall(this, request, false /* for web socket */);
}
接下来看看RealCall.newRealCall
方法是如何创建出来Call
的
static RealCall newRealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
RealCall call = new RealCall(client, originalRequest, forWebSocket);
call.eventListener = client.eventListenerFactory().create(call);
return call;
}
默认情况下,这里的eventListener
传入的是
public static final EventListener NONE = new EventListener() {};
在看new RealCall
调用
//forWebSocket 如果不使用webSocket的话为false
private RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
//初始化重试请求拦截器,用户处理失败或者重定向
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client);
//异步请求超时处理
this.timeout = new AsyncTimeout() {
@Override
protected void timedOut() {
cancel();
}
};
this.timeout.timeout(client.callTimeoutMillis(), MILLISECONDS);
}
3-3、同步调用execute()
public Response execute() throws IOException {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
//超时计算开始时间
timeout.enter();
eventListener.callStart(this);
try {
//加入标记数组,方便处理取消,完成等操作
client.dispatcher().executed(this);
//通过拦截器链,获取请求结果
Response result = getResponseWithInterceptorChain();
if (result == null) throw new IOException("Canceled");
return result;
} catch (IOException e) {
e = timeoutExit(e);
eventListener.callFailed(this, e);
throw e;
} finally {
client.dispatcher().finished(this);
}
}
可以发现同步调用的请求结果主要是依赖getResponseWithInterceptorChain
得到。
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);
}
对于上面的这些拦截器,后面专门针对每一个做详细的介绍。
3-4、异步调用enqueue(Callback callback)
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));
}
主要是调用了Dispatcher
的enqueue
方法。
void enqueue(AsyncCall call) {
synchronized (this) {
//线程取消等操作标志位
readyAsyncCalls.add(call);
}
//
promoteAndExecute();
}
在看看promoteAndExecute
方法
//迭代执行调用
for (int i = 0, size = executableCalls.size(); i < size; i++) {
AsyncCall asyncCall = executableCalls.get(i);
//异步调用请求连接,这里传入的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;
}
接下来看看executeOn
方法,其中关键代码只有一句executorService.execute(this);
,其实就是加入线程池调用,这里传入的是AsyncCall
继承的是NamedRunnable
,而NamedRunnable
实现自Runnable
对象。在NamedRunnable
的run
方法中执行了AsyncCall
的execute
方法。
...
//执行调用链,返回Response
Response response = getResponseWithInterceptorChain();
if (retryAndFollowUpInterceptor.isCanceled()) {
signalledCallback = true;
//回掉请求失败
responseCallback.onFailure(RealCall.this, new IOException("Canceled"));
} else {
signalledCallback = true;
//回掉请求成功
responseCallback.onResponse(RealCall.this, response);
}
...
这里的responseCallback
就是在enqueue
时候传入的callback,由于callback是在ui线程中,所以该操作就直接完成了了线程切换操作,返回的结果是在ui线程中。
基本的调用流程在这里就全部完成了,下篇文章将说明下拦截器链中的所有拦截器方法。