OkHttp解析
今天花了一天时间研究了下OkHttp3的内部原理,记录在此处以便后期查阅

我们先来看下基本的使用方式:
public void sendHttpRequest(String url,Callback callback){
OkHttpClient client=new OkHttpClient();
Request request=new Request.Builder().url(url).build();
client.newCall(request).enqueue(callback); //异步执行
try {
client.newCall(request).execute();//同步执行
} catch (IOException e) {
e.printStackTrace();
}
}
接下来的分析就以异步执行开始
@Override
public Call newCall(Request request) {
return new RealCall(this, request, false /* for web socket */);
}
RealCall(OkHttpClient client, Request originalRequest, boolean forWebSocket) {
this.client = client;
this.originalRequest = originalRequest;
this.forWebSocket = forWebSocket;
this.retryAndFollowUpInterceptor = new RetryAndFollowUpInterceptor(client, forWebSocket);
}
RealCall的enqueue()方法
@Override public void enqueue(Callback responseCallback) {
synchronized (this) {
if (executed) throw new IllegalStateException("Already Executed");
executed = true;
}
captureCallStackTrace();
client.dispatcher().enqueue(new AsyncCall(responseCallback));
}
synchronized void enqueue(AsyncCall call) {
if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {//同时发起的请求不能超过最大请求数,如果超过了,就放入readyAsyncCalls队列
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 的run方法 ,在父类 NamedRunnable 中
@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();//由子类实现
@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);
}
}
现在我们进入 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);
return chain.proceed(originalRequest);
}
public Response proceed(Request request, StreamAllocation streamAllocation, HttpCodec httpCodec,
Connection connection) throws IOException {
//........
RealInterceptorChain next = new RealInterceptorChain(
interceptors, streamAllocation, httpCodec, connection, index + 1, request);
Interceptor interceptor = interceptors.get(index);
Response response = interceptor.intercept(next); //拦截器中都会调用 chain.proceed(request)来获取response,产生递归,依次调用各个拦截器的intercept方法 //......... return response;
}
其他拦截器就不看了,我们来看看比较重要的缓存拦截器
@Override public Response intercept(Chain chain) throws IOException {
Response cacheCandidate = cache != null
? cache.get(chain.request())
: null;//查看是否有缓存
CacheStrategy strategy = new CacheStrategy.Factory(now, chain.request(), cacheCandidate).get();//根据缓存响应头返回的一些信息来制定缓存策略,是从缓存取还是从网络上取
Request networkRequest = strategy.networkRequest;
Response cacheResponse = strategy.cacheResponse;
//..............
// If we're forbidden from using the network and the cache is insufficient, fail. 禁止使用网络并且缓存也是空的,请求失败
if (networkRequest == null && cacheResponse == null) {
return new Response.Builder()
.request(chain.request())
.protocol(Protocol.HTTP_1_1)
.code(504)
.message("Unsatisfiable Request (only-if-cached)")
.body(Util.EMPTY_RESPONSE)
.sentRequestAtMillis(-1L)
.receivedResponseAtMillis(System.currentTimeMillis())
.build();
}
// If we don't need the network, we're done. 如果不需要网络,直接返回缓存
if (networkRequest == null) {
return cacheResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.build();
}
Response networkResponse = null;
try {
networkResponse = chain.proceed(networkRequest);
} finally {
// If we're crashing on I/O or otherwise, don't leak the cache body.
if (networkResponse == null && cacheCandidate != null) {
closeQuietly(cacheCandidate.body());
}
}
// If we have a cache response too, then we're doing a conditional get.
if (cacheResponse != null) {
if (networkResponse.code() == HTTP_NOT_MODIFIED) {
Response response = cacheResponse.newBuilder()
.headers(combine(cacheResponse.headers(), networkResponse.headers()))
.sentRequestAtMillis(networkResponse.sentRequestAtMillis())
.receivedResponseAtMillis(networkResponse.receivedResponseAtMillis())
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
networkResponse.body().close();
// Update the cache after combining headers but before stripping the
// Content-Encoding header (as performed by initContentStream()).
cache.update(cacheResponse, response); //更新缓存
return response;
} else {
closeQuietly(cacheResponse.body());
}
}
Response response = networkResponse.newBuilder()
.cacheResponse(stripBody(cacheResponse))
.networkResponse(stripBody(networkResponse))
.build();
if (HttpHeaders.hasBody(response)) {
CacheRequest cacheRequest = maybeCache(response, networkResponse.request(), cache);
response = cacheWritingResponse(cacheRequest, response);
}
return response;
}
太晕了,来张图看看吧

OkHttp解析的更多相关文章
- # Okhttp解析—Interceptor详解
Okhttp解析-Interceptor详解 Interceptor可以说是okhttp的精髓之一,Okhttp重写请求/响应.重试.缓存响应等操作,基本都是在各个Interceptor中完成的,上篇 ...
- Okhttp解析—Okhttp概览
Okhttp解析-Okhttp概览 Okhttp作为目前Android使用最为广泛的网络框架之一,我们有必要去深入了解一下,本文是Okhttp解析的第一篇,主要是从宏观上认识Okhttp整个架构是如何 ...
- Android使用OKHTTP解析JSON数据
为了代码重用,我们首先封装一个类.这个类是HttpUtil HttpUtil.java package com.example.asus.networktest; import okhttp3.OkH ...
- okhttp 解析respone:
android,retrofit,okhttp,日志拦截器,使用拦截器Interceptor统一打印请求与响应的json: https://blog.csdn.net/qq_37043246/arti ...
- java.lang.IllegalArgumentException: Illegal character in query at index 261
在BaseFragment中使用了LoadingPage,而LoadingPage的联网加载使用的是AsyncHttpClient.一直报java.lang.IllegalArgumentExcept ...
- Android + HTML5 混合开发
摘要: 对于 Android + HTML5 混合开发以下的观点仅仅是我的个人观点,如果有什么不对的地方请指正 简介: 混合开发的 App(Android + HTML5)就是在一个 App 中内嵌一 ...
- MaterialDesign学习项目
概述 该项目主要用来学习Material Design Support Library和一些android其他技术,也借鉴了网上一些其他优秀的学习资源.该项目目前主要分为俩大部分(后期可能会有一些增加 ...
- Android的路接下来该怎么走?
其实想写这篇文章好久了,很多小伙伴们也经常在群里探讨android移动开发者的走向,一部分人都想多快好省,间歇性踌躇满志.持续性混吃等死 ,只想用CV的开发模式们快速完成工作,然后回家王者农药.其实这 ...
- XRecyclerView上拉刷新下拉加载
效果图: 首先要添加依赖: //xrecyclerviewimplementation 'com.jcodecraeer:xrecyclerview:1.3.2'//Gsonimplementatio ...
随机推荐
- 机器学习优化方法总结比较(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)
SGD: 此处的SGD指mini-batch gradient descent,关于batch gradient descent, stochastic gradient descent, 以及 mi ...
- ElasticSearch生产模式开发模式的区分
ElasticSearch生产模式开发模式的区分 network.host: 0.0.0.0 如果network.host不是localhost就是生产模式, 开发模式中的warning就是生产模式中 ...
- OCP47:155
- zedboard中OLED源码
#include <stdio.h> #include "platform.h" #include "xil_types.h" #include & ...
- eclipse新建android项目出现非常多错误
如图所看到的: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSGFycnlXZWFzbGV5/font/5a6L5L2T/fontsize/400/fil ...
- LeetCode(3)题解: Longest Palindromic Substring
https://leetcode.com/problems/longest-palindromic-substring/ 题目: Given a string S, find the longest ...
- LeetCode(27)题解:Remove Element
https://leetcode.com/problems/remove-element/ Given an array and a value, remove all instances of th ...
- java线程阻塞(sleep,suspend,resume,yield,wait,notify)
为了解决对共享存储区的访问冲突,Java 引入了同步机制,现在让我们来考察多个线程对共享资源的访问,显然同步机制已经不够了,因为在任意时刻所要求的资源不一定已经准备好了被访问,反过来,同一时刻准备好了 ...
- firefox 45 版本
在做项目的时候,发现45版本的firefox浏览器.声明函数要放在调用者的上方.而firefox的47,48版本则没有这种情况发生.
- Safair css hack
一下方式不会影响chrome浏览器样式 _::-webkit-full-page-media, _:future, :root .class{ /*此处放css样式*/ }