本章主要介绍Okhttp的使用和和源码分析
- 准备工作
- 常见用法
- OkHttp更好的封装
- OkHttp的源码分析
一. 准备工作
在gradle中添加依赖
implementation 'com.squareup.okio:okio:1.7.0'
implementation 'com.squareup.okhttp3:okhttp:3.2.0'
添加网络权限
<uses-permission android:name="android.permission.INTERNET"/>
二. 常见用法
- get异步请求
private void getAsynHttp() {
Request.Builder requestBuilder = new Request.Builder().url("http://www.baidu.com");
requestBuilder.method("GET", null);
Request request = requestBuilder.build();
Call mcall = mOkHttpClient.newCall(request);
mcall.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Toast.makeText(getApplicationContext(), "请求失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String str = response.body().string();
Log.i(TAG, str);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
}
});
}
});
}
- post异步请求
private void postAsynHttp() {
RequestBody formBody = new FormBody.Builder()
.add("ip", "59.108.54.37")
.build();
Request request = new Request.Builder()
.url("http://ip.taobao.com/service/getIpInfo.php")
.post(formBody)
.build();
OkHttpClient mOkHttpClient = new OkHttpClient();
Call call = mOkHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Toast.makeText(getApplicationContext(), "请求失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
String str = response.body().string();
Log.d(TAG, str);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
}
});
}
});
}
只是添加了一个FormBody
- 异步上传文件
private void postAsynFile() {
String filepath = "";
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
filepath = Environment.getExternalStorageDirectory().getAbsolutePath();
} else {
filepath = getFilesDir().getAbsolutePath();
}
File file = new File(filepath, "wangshu.txt");
Request request = new Request.Builder()
.url("https://api.github.com/markdown/raw")
.post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))
.build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
}
@Override
public void onResponse(Call call, Response response) throws IOException {
Log.d(TAG, response.body().string());
}
});
}
定义文件类型再调用RequestBody方法就ok
- 异步下载文件
private void downAsynFile() {
String url = "https://img-my.youkuaiyun.com/uploads/201603/26/1458988468_5804.jpg";
Request request = new Request.Builder().url(url).build();
mOkHttpClient.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Toast.makeText(getApplicationContext(), "文件下载失败", Toast.LENGTH_SHORT).show();
}
@Override
public void onResponse(Call call, Response response) {
InputStream inputStream = response.body().byteStream();
FileOutputStream fileOutputStream = null;
String filepath = "";
try {
if (Environment.getExternalStorageState().equals(
Environment.MEDIA_MOUNTED)) {
filepath = Environment.getExternalStorageDirectory().getAbsolutePath();
} else {
filepath = getFilesDir().getAbsolutePath();
}
File file = new File(filepath, "wangshu.jpg");
if (null != file) {
fileOutputStream = new FileOutputStream(file);
byte[] buffer = new byte[2048];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
fileOutputStream.write(buffer, 0, len);
}
fileOutputStream.flush();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "文件存储成功", Toast.LENGTH_SHORT).show();
}
});
} else {
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getApplicationContext(), "文件存储失败", Toast.LENGTH_SHORT).show();
}
});
}
} catch (IOException e) {
Log.e(TAG, "IOException");
e.printStackTrace();
}
}
});
}
调用response.body().byteStream();得到输入流然后就是文件操作了
- 初始化okClient
private void initOkHttpClient() {
File sdcache = getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
mOkHttpClient = builder.build();
}
在okHttp中,所有所有对于连接的初始化操作都在OkHttpClient.Builder进行,这里设置了超市时间和缓存。
- 取消请求
当用户离开应用程序或者跳转到其他页面的时候,我们可以取消任务节省网络资源。
简单的方法就是在Request.Builder.tag中分配一个标签,然后我们就能用OkHtppClient.cancel(Object tag)来取消任务
三. OkHttp更好的封装
public class OkHttpEngine {
private static volatile OkHttpEngine mInstance;
private OkHttpClient mOkHttpClient;
private Handler mHandler;
// 双重检验锁创建OkHttpEngine单例
public static OkHttpEngine getInstance(Context context) {
if (mInstance == null) {
synchronized (OkHttpEngine.class) {
if (mInstance == null) {
mInstance = new OkHttpEngine(context);
}
}
}
return mInstance;
}
// 在构造函数中初始化Client和handler
private OkHttpEngine(Context context) {
File sdcache = context.getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
OkHttpClient.Builder builder = new OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.cache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
mOkHttpClient=builder.build();
mHandler = new Handler();
}
/**
* 异步get请求
* @param url
* @param callback
*/
public void getAsynHttp(String url, ResultCallback callback) {
final Request request = new Request.Builder()
.url(url)
.build();
Call call = mOkHttpClient.newCall(request);
dealResult(call, callback);
}
private void dealResult(Call call, final ResultCallback callback) {
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
sendFailedCallback(call.request(), e, callback);
}
@Override
public void onResponse(Call call, Response response) throws IOException {
sendSuccessCallback(response.body().string(), callback);
}
private void sendSuccessCallback(final String str, final ResultCallback callback) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (callback != null) {
try {
callback.onResponse(str);
} catch (IOException e) {
e.printStackTrace();
}
}
}
});
}
private void sendFailedCallback(final Request request, final Exception e, final ResultCallback callback) {
mHandler.post(new Runnable() {
@Override
public void run() {
if (callback != null)
callback.onError(request, e);
}
});
}
});
}
public abstract class ResultCallback{
public abstract void onError(Request request, Exception e);
public abstract void onResponse(String str) throws IOException;
}
}
请求网络的时候是用Handler将请求结果回调给UI线程,所以我们想要请求网络的时候只需要调用OkHttpEngine的getAsynHttp方法并写一个ResultCallback回调就可以了。
四. OkHttp的源码分析
我们从使用开始,一步步剖析OkClient的源码实现
//下面是一段Kotlin代码
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val request = Request.Builder().url("https://www.baidu.com/").method("get", null).build()
OkHttpClient().newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call?, e: IOException?) {
Log.d("onClient", "isBad")
}
override fun onResponse(call: Call?, response: Response?) {
Log.e("onClient", "isOk")
}
})
}
我们把重点关注在 OkHttpClient().newCall(request).enqueue()
这个方法中
newCall方法:
// OkHttpClint中的newCall方法
@Override public Call newCall(Request request) {
return new RealCall(this, request);
}
实例化一个RealCall类,RealCall实现了Call接口,看一下Call是干什么的
,这里保留了源码的英文注释
// A call is a request that has been prepared for execution.
public interface Call {
// Invokes the request immediately, and blocks until the response can be processed or is in error.
Response execute() throws IOException;
// Schedules the request to be executed at some point in the future.
void enqueue(Callback responseCallback);
void cancel();
boolean isExecuted();
boolean isCanceled();
interface Factory {
Call newCall(Request request);
}
}
然后我们继续看OkHttpClient().newCall(request).enqueue()
的enqueue方法
// RealCall中的enqueue方法
void enqueue(Callback responseCallback, boolean forWebSocket) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
client.dispatcher().enqueue(new AsyncCall(responseCallback, forWebSocket));
}
其中这个参数responseCallback就是源码介绍开头中OkHttpClient().newCall(request).enqueue()
传入的callback
我们这里可以看到,真正处理这个Callback的并不是RealCall,而是dispatcher(),这个就是调度器,看看他的类声明 public final class Dispatcher
是一个不变类,也就是说不能被重写。
我们看一下调度器Dispatcher中的enqueue方法:
// Dispatcher类的enqueue方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
这个方法用了synchronized声明。看到这么多全局的变量,感觉有点烦,没事,其实很简单,我们看一下Dispatcher的声明:
// Dispatcher类的成员变量
private int maxRequests = 64;
private int maxRequestsPerHost = 5;
/** Executes calls. Created lazily. */
private 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<>();
是不是感觉很清晰,很简单
我们回头看这段代码
// Dispatcher类的enqueue方法
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
runningAsyncCalls.add(call);
executorService().execute(call);
} else {
readyAsyncCalls.add(call);
}
}
很简单,如果可以这个符合可以运行的条件,就把它加到runningAsyncCalls队列中,然后调用execute执行,否则加到readyAsyncCalls准备队列中
ok,我们把关注点放在这个方法中
executorService().execute(call);
// Dispatcher的executorService方法
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;
}
// 对比一下newCachedThreadPool,简直就是一毛一样好吧
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
我们知道CachedThreadPool实际上就是一个无限容量,但是队列中只有一个线程的线程池。这种线程池比较适合任务比较多,但是任务比较小的情况。
execute(Runnable run)调度方法最后会调用调用这个runnable的run方法,因为这个call是AsyncCall类,我们看看这个类的run方法:
final class AsyncCall extends NamedRunnable {
private final Callback responseCallback;
private final boolean forWebSocket;
private AsyncCall(Callback responseCallback, boolean forWebSocket) {
super("OkHttp %s", originalRequest.url().toString());
this.responseCallback = responseCallback;
this.forWebSocket = forWebSocket;
}
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
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!
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
}
没有run方法呀,怎么肥事?看看它继承的类NamedRunnable搞了什么。
public abstract class NamedRunnable implements Runnable {
protected final String name;
public NamedRunnable(String format, Object... args) {
this.name = String.format(format, args);
}
@Override public final void run() {
String oldName = Thread.currentThread().getName();
Thread.currentThread().setName(name);
try {
execute();
} finally {
Thread.currentThread().setName(oldName);
}
}
protected abstract void execute();
}
原来是它在run方法执行了execute方法,行吧,其实一样,线程池最后执行的是AsyncCall的execute方法。ojbk,来看一下吧!
// AsyncCall的execute方法
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
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!
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
别急,我们一个个往下面看,先看这个方法:getResponseWithInterceptorChain
private Response getResponseWithInterceptorChain(boolean forWebSocket) throws IOException {
Interceptor.Chain chain = new ApplicationInterceptorChain(0, originalRequest, forWebSocket);
return chain.proceed(originalRequest);
}
ApplicationInterceptorChain 从名字可以猜测到,他是一个拦截链,看一下吧!
// ApplicationInterceptorChain类的proceed方法
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
// 得到了当前拦截器
Interceptor interceptor = client.interceptors().get(index);
// 拦截操作,所有拦截器(除了最后一个)都会阻塞到这里
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor
+ " returned null");
}
return interceptedResponse;
}
return getResponse(request, forWebSocket);
}
}
看到这段,有点发蒙
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
为什么还要创建一个chain呢,原来index代表当前拦截器所在的位置,比如一共有五个拦截器,拦截器“G”在第二个,那你要做的是将“G”拦截器拦截在第一个拦截器之后。get到了吗?
Response interceptedResponse = interceptor.intercept(chain);
这个方法为什么会拦住所有的拦截器,大家可能不明白,我就随便创建一个拦截器(拦截发出的请求和响应的日志)出来,大家就知道了。
class LoggingInterceptor implements Interceptor {
@Override public Response intercept(Interceptor.Chain chain) throws IOException {
Request request = chain.request();
long t1 = System.nanoTime();
logger.info(String.format("Sending request %s on %s%n%s",
request.url(), chain.connection(), request.headers()));
Response response = chain.proceed(request);
long t2 = System.nanoTime();
logger.info(String.format("Received response for %s in %.1fms%n%s",
response.request().url(), (t2 - t1) / 1e6d, response.headers()));
return response;
}
}
大家能够明白吗,这里我画一张图:
这个有点类似Spirng中的拦截器,其实是一个道理。
ok,我们讨论完了拦截器。回到AsyncCall的execute方法。
// AsyncCall的execute方法
@Override protected void execute() {
boolean signalledCallback = false;
try {
Response response = getResponseWithInterceptorChain(forWebSocket);
if (canceled) {
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!
logger.log(Level.INFO, "Callback failure for " + toLoggableString(), e);
} else {
responseCallback.onFailure(RealCall.this, e);
}
} finally {
client.dispatcher().finished(this);
}
}
responseCallback.onFailure(RealCall.this, responseCallback.onResponse(RealCall.this, response);
这里正是我们重写的Callback的两个方法。
好了,做了这么久的前戏,也该开始网络请求了吧?看这个方法
client.dispatcher().finished(this);
是调度器的finish方法。
// Dispatcher类的finished方法
synchronized void finished(AsyncCall call) {
if (!runningAsyncCalls.remove(call)) throw new AssertionError("AsyncCall wasn't running!");
promoteCalls();
}
这里简单地把call从运行队列中移走了。看一下PromoteCalls方法:
// Dispatcher类中的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.
}
}
很简单,running的一个call被消化了,这个队列也就有了空位置,这时候ready队列有call乘机上位。等等,说好的网络请求呢,在哪?是不是哪里疏忽了?
我们分析到AsyncCall的execute方法的时候,还记得它做了什么吗,它用一大堆拦截链拦截他,然后在最后 client.dispatcher().finished(this);对调度器Dispactcher的两个队列进行收尾对吧?
于是我们大概分析到网络请求操作在它们中间!果然在拦截器中间ApplicationInterceptorChain类的proceed方法找到啦!
// ApplicationInterceptorChain类的proceed方法
@Override public Response proceed(Request request) throws IOException {
// If there's another interceptor in the chain, call that.
if (index < client.interceptors().size()) {
Interceptor.Chain chain = new ApplicationInterceptorChain(index + 1, request, forWebSocket);
// 得到了当前拦截器
Interceptor interceptor = client.interceptors().get(index);
// 拦截操作,所有拦截器(除了最后一个)都会阻塞到这里
Response interceptedResponse = interceptor.intercept(chain);
if (interceptedResponse == null) {
throw new NullPointerException("application interceptor " + interceptor
+ " returned null");
}
return interceptedResponse;
}
return getResponse(request, forWebSocket);
}
}
网络请求在这里:getResponse(request, forWebSocket);
这个方法又臭又长,这里我把重要的贴出来。
Response getResponse(Request request, boolean forWebSocket) throws IOException {
engine.sendRequest();
engine.readResponse();
}
喵喵喵!就这么短
一个个看啰!
HttpEngine的sendRequest方法也很复杂,主要解决的是缓存问题,我们就不展开了,不然要要要讲到明年!
// HttpEngine的sendRequest方法
public void sendRequest() throws RequestException, RouteException, IOException {
if (cacheStrategy != null) return;
if (httpStream != null) throw new IllegalStateException();
Request request = networkRequest(userRequest);
//获取Client中的Cache,同时Cache在初始化的时候读取缓存目录中曾经请求过的所有信息。
InternalCache responseCache = Internal.instance.internalCache(client);
Response cacheCandidate = responseCache != null
? responseCache.get(request)
: null;
long now = System.currentTimeMillis();
cacheStrategy = new CacheStrategy.Factory(now, request, cacheCandidate).get();
//网络请求
networkRequest = cacheStrategy.networkRequest;
//缓存的响应
cacheResponse = cacheStrategy.cacheResponse;
if (responseCache != null) {
//记录当前请求是网络发起的还是缓存发起的
responseCache.trackResponse(cacheStrategy);
}
if (cacheCandidate != null && cacheResponse == null) {
closeQuietly(cacheCandidate.body()); // The cache candidate wasn't applicable. Close it.
}
// 不进行网络请求并且缓存不存在或者过期,返回504错误
if (networkRequest == null && cacheResponse == null) {
userResponse = new Response.Builder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(EMPTY_BODY)
.build();
return;
}
// 不进行网络请求而且缓存可以使用,则直接返回缓存
if (networkRequest == null) {
userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.build();
userResponse = unzip(userResponse);
return;
}
// 需要访问网络时
boolean success = false;
try {
httpStream = connect();
httpStream.setHttpEngine(this);
cacheCandidate是上次与服务器交互时缓存的Response,这里的缓存均基于Map。key是请求中url的md5,value是在文件中查到的缓存,页面置换算法基于LRU。
通过cacheStrategy我们可以得到networkRequest和cacheResponse,代表网络请求和缓存是否存在。如果networkRequest和cacheResponse都为null的时候,返回504错误,当networkRequest为null时,也就是不进行网络请求时,就可以直接返回缓存,其他情况就请求网络。
我们粗略看一下readResponse()方法:
public void readResponse() throws IOException {
Response networkResponse;
if (forWebSocket) {
httpStream.writeRequestHeaders(networkRequest);
// 读取网络响应
networkResponse = readNetworkResponse();
} else if (!callerWritesRequestBody) {
// 检查缓存是否可用,如果可用则使用当前缓存的Response,关闭网络连接,释放连接
networkResponse = new NetworkInterceptorChain(0, networkRequest).proceed(networkRequest);
} else {
// Emit the request body's buffer so that everything is in requestBodyOut.
if (bufferedRequestBody != null && bufferedRequestBody.buffer().size() > 0) {
bufferedRequestBody.emit();
}
// Emit the request headers if we haven't yet. We might have just learned the Content-Length.
if (sentRequestMillis == -1) {
if (OkHeaders.contentLength(networkRequest) == -1
&& requestBodyOut instanceof RetryableSink) {
long contentLength = ((RetryableSink) requestBodyOut).contentLength();
networkRequest = networkRequest.newBuilder()
.header("Content-Length", Long.toString(contentLength))
.build();
}
httpStream.writeRequestHeaders(networkRequest);
}
// Write the request body to the socket.
if (requestBodyOut != null) {
if (bufferedRequestBody != null) {
// This also closes the wrapped requestBodyOut.
bufferedRequestBody.close();
} else {
requestBodyOut.close();
}
if (requestBodyOut instanceof RetryableSink) {
httpStream.writeRequestBody((RetryableSink) requestBodyOut);
}
}
networkResponse = readNetworkResponse();
}
receiveHeaders(networkResponse.headers());
// If we have a cache response too, then we're doing a conditional get.
if (cacheResponse != null) {
if (validate(cacheResponse, networkResponse)) {
userResponse = cacheResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
releaseStreamAllocation();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
InternalCache responseCache = Internal.instance.internalCache(client);
responseCache.trackConditionalCacheHit();
responseCache.update(cacheResponse, stripBody(userResponse));
userResponse = unzip(userResponse);
return;
} else {
closeQuietly(cacheResponse.body());
}
}
userResponse = networkResponse.newBuilder()
.request(userRequest)
.priorResponse(stripBody(priorResponse))
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (hasBody(userResponse)) {
maybeCache();
userResponse = unzip(cacheWritingResponse(storeRequest, userResponse));
}
}
这个方法做的是解析HTTP响应报头。如果有缓存而且可用,则用缓存的数据并更新缓存,否则则用网络请求返回的数据。
总结完了,大家应该会觉得很乱,这里粗略画个图帮助大家理解。