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 ...
随机推荐
- Mathematica 表达式求值
表达式是变量之间的运算关系.表达式求值就是对变量赋值并运算出结果的过程. 针对于Mathematica中的表达式.有两种方法获得其值. 一是对对应的变量直接赋值.这样对应的表达式在调用时便会直接运算得 ...
- socket 网络编程高速入门(一)教你编写基于UDP/TCP的服务(client)通信
由于UNIX和Win的socket大同小异,为了方便和大众化,这里先介绍Winsock编程. socket 网络编程的难点在入门的时候就是对基本函数的了解和使用,由于这些函数的结构往往比較复杂,參数大 ...
- Java集合框架:Arrays工具类
java.util.Arrays类能方便地操作数组,它提供的方法都是静态的.整个Arrays工具类的实现有3000+行.可是归纳总结一下可知它有下面功能(9个): 1. asList 定义: @Saf ...
- csu1116 Kingdoms 最小生成树-枚举状态
题目链接: csu 1116 题意: 有一幅双向图连接N个城市(标号1~n,1表示首都) 每一个城市有一个价值W. 地震摧毁了全部道路,现给出可修复的m条道路并给出修复每条道路所需的费用 问在总费用 ...
- ACM在线题库
现在网上有许多题库,大多是可以在线评测,所以叫做Online Judge.除了USACO是为IOI准备外,其余几乎全部是大学的ACM竞赛题库. USACO http://ace.delos.com/u ...
- sanic官方文档解析之蓝图
1,蓝图(Blueprints) 蓝图可用于子路由的应用,代替增加路由的存在,蓝图的定义和增加路由的方法相似,灵活的在应用中注册,并且可插拔的方式. 尤其是在大型应用中使用蓝图的时候在你逻辑打断的地方 ...
- Spring Base
1.在java开发领域,Spring相对于EJB来说是一种轻量级的,非侵入性的Java开发框架,曾经有两本很畅销的书<Expert one-on-one J2EE Design and Deve ...
- SD/MMC异同
该文章转自:http://www.imhan.com/archives/12/ 经常看到SD/MMC这样的写法,在这里稍微总结一下SD卡和MMC卡的异同点吧. 首先,两者在外型的规格上是几乎一致的.而 ...
- vue开发总结(一)
vue使用快一个多月了,从移动端到PC端,踩过的坑也不少.项目的开发是基于element ui 与 mint ui 组件库,下面总结下项目中的一些知识点: 一.网页数据请求 首次进入页面,需要请求数据 ...
- 各种DP总结
一.数位DP 1.含有或不含某个数“xx”: HDU3555 Bomb HDU2089 不要62 2.满足某些条件,如能整除某个数,或者数位上保持某种特性: HDU3652 B-number Code ...