Android之OkHttp网络架构源码深入分析(揭开神秘的面纱)(2)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip204888 (备注Android)
img

正文

return call;

}

RealCall 是 Call 的实现类,Call 定义了请求相关的操作,例如同步异步、取消请求等方法。所以后续的请求相关操作基本都是在调用 Call 定义的方法,而这些方法真正的执行是它的实现类 RealCall

2.4请求数据

请求的整个预览图

同步请求 代码如下:

@Override public Response execute() throws IOException {

synchronized (this) {

if (executed) throw new IllegalStateException(“Already Executed”);

executed = true;

}

captureCallStackTrace();

eventListener.callStart(this);

try {

client.dispatcher().executed(this);// (1)

Response result = getResponseWithInterceptorChain();// (2)

if (result == null) throw new IOException(“Canceled”);

return result;

} catch (IOException e) {

eventListener.callFailed(this, e);

throw e;

} finally {

client.dispatcher().finished(this);// (3)

}

}

/Dispatcher/

synchronized void executed(RealCall call) {

runningSyncCalls.add(call);

}

// RealCall.java

Response getResponseWithInterceptorChain() throws IOException {

// Build a full stack of interceptors.

// 创建一个拦截器链

List 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));

// originalRequest:我们写的 request

Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,

originalRequest, this, eventListener, client.connectTimeoutMillis(),

client.readTimeoutMillis(), client.writeTimeoutMillis());

return chain.proceed(originalRequest);

}

①根据上面源码我们可以知道getResponseWithInterceptorChain()返回了 Response ,由此可见访问网络从服务器获取数据的操作都在getResponseWithInterceptorChain()内

②这里引入了拦截器链,Request 需要通过拦截器链接收相应的处理最后才会发送到服务器并获取服务器返回的响应

拦截器执行顺序

  • 应用拦截器:开发者添加的拦截器

  • retryAndFollowUpInterceptor:负责失败重连操作,以及重定向,如果 call 被取消会抛出 IOException

  • BridgeInterceptor:作为网络层与应用层之间的桥梁,把(应用层请求)user request转化为(网络层请求)network request,然后向服务器发送network request,得到(网络层响应)network reseponse后转化为(应用层响应) user response

  • CacheInterceptor:处理缓存中的 requests 以及把 responses 写到缓存

  • ConnectInterceptor:负责与目标服务器建立连接

  • 网络拦截器:开发者添加的拦截器

  • CallServerInterceptor:拦截器链的最后一个拦截器,负责向服务器发送请求和从服务器获取响应数据

异步请求代码如下

// RealCall.java

@Override public void enqueue(Callback responseCallback) {

synchronized (this) { // 如果这个 call 已经被执行过,抛异常

if (executed) throw new IllegalStateException(“Already Executed”);

executed = true;

}

captureCallStackTrace();

eventListener.callStart(this);

client.dispatcher().enqueue(new AsyncCall(responseCallback));

}

AsyncCall call = new AsyncCall(responseCallback);

Dispatcher dispatcher = client.dispatcher();

dispatcher.enqueue(call);

把 responseCallback 封装成 AsyncCall

返回了一个 Dispatcher

调用任务调度器 Dispatcher 的 enqueue() 异步执行 call

解一下 Dispatcher

// Dispatcher.java

public final class Dispatcher {

// 同步请求和异步请求之和最大值

private int maxRequests = 64;

// 同一个 host 请求数最大值

private int maxRequestsPerHost = 5;

private @Nullable Runnable idleCallback;

/** Executes calls. Created lazily. */

/** 用于执行请求的线程池,且是懒加载的 */

private @Nullable ExecutorService executorService;

/** Ready async calls in the order they’ll be run. */

/** 等待被执行的异步请求 */

private final Deque readyAsyncCalls = new ArrayDeque<>();

/** Running asynchronous calls. Includes canceled calls that haven’t finished yet. */

/** 正在执行的异步请求,包括已经被取消但未完成的请求 */

private final Deque runningAsyncCalls = new ArrayDeque<>();

/** Running synchronous calls. Includes canceled calls that haven’t finished yet. */

/** 正在执行的同步请求,包括已经被取消但未完成的请求 */

private final Deque runningSyncCalls = new ArrayDeque<>();

public synchronized ExecutorService executorService() {

if (executorService == null) {

// 核心线程数为0,最大线程数为 Integer.MAX_VALUE ,空闲线程最多存活60秒

executorService = new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60, TimeUnit.SECONDS,

new SynchronousQueue(), Util.threadFactory(“OkHttp Dispatcher”, false));

}

return executorService;

}

synchronized void enqueue(AsyncCall call) {

if (runningAsyncCalls.size() < maxRequests

&& runningCallsForHost(call) < maxRequestsPerHost) {

// 如果正在执行的异步请求数没有达到最大值

// 就放到 runningAsyncCalls 标记为正在执行

runningAsyncCalls.add(call);

// 用 executorService 执行这个异步请求

executorService().execute(call);

} else {

// 如果正在执行的异步请求数达到最大值

// 就放到 readyAsyncCalls 标记为等待执行

readyAsyncCalls.add(call);

}

}

}

Dispatcher 是任务调度器,内部建立了一个线程池 ExecutorService ,而且维护了三个集合:

  • readyAsyncCalls : 等待被执行的异步请求集合

  • runningAsyncCalls : 正在执行的异步请求集合,包括已经被取消但未完成的请求

  • runningSyncCalls : 正在执行的同步请求集合,包括已经被取消但未完成的请求

所有异步请求都交由线程池 ExecutorService 来执行。

线程池其实是 ThreadPoolExecutor ,且核心线程数为 0 、最大线程数为Integer.MAX_VALUE、空闲线程存活最大时间为60秒,即所有线程执行完之后空闲60秒就会被销毁,而且存在线程过多导致内存溢出问题等问题,但是在 Dispatcher 的调度下是不会发生线程过多情况的,因为 Dispatcher 限制了正在执行的请求数(同步和异步之和)最大为64,同一个host下请求同时存在数最大值为 5 。

线程池会调用线程执行 AsyncCall 的 execute()

// RealCall.java

final class AsyncCall extends NamedRunnable {

@Override protected void execute() {

boolean signalledCallback = false;

try {

// 通过拦截器链得到从服务器获取的响应 Response

Response response = getResponseWithInterceptorChain();

// 如果 retryAndFollowUpInterceptor.cancel() 被调用过就报异常

if (retryAndFollowUpInterceptor.isCanceled()) {

signalledCallback = true; // 标记 callback 回调函数已被调用

responseCallback.onFailure(RealCall.this, new IOException(“Canceled”));

} else {

// 到这里表示获取响应成功

signalledCallback = true; // 标记 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 {

eventListener.callFailed(RealCall.this, e);

responseCallback.onFailure(RealCall.this, e);

}

} finally {

// 最后要通知 dispatcher 标记该任务已完成

client.dispatcher().finished(this);

}

}

}

AsyncCall 的 execute() 逻辑很简单,getResponseWithInterceptorChain() 我们已经在上篇文章中了解过了,获取 Response 之后只需要判断是回调 responseCallback 的 onFailure() 还是 onResponse(),所以 enqueue() 中的回调方法是在子线程中被调用的,当然最后还要调用 finished() 通知 Dispatcher 该任务已经完成了,需要从runningAsyncCalls中移除该任务。

Dispatcher 的判断就在每个异步任务结束时调用的 finish(call) 内

// Dispatcher.java

// 异步请求

void finished(AsyncCall call) {

finished(runningAsyncCalls, call, true);

}

// 同步请求

void finished(RealCall call) {

finished(runningSyncCalls, call, false);

}

private void finished(Deque calls, T call, boolean promoteCalls) {

int runningCallsCount;

Runnable idleCallback;

synchronized (this) {

if (!calls.remove(call)) throw new AssertionError(“Call wasn’t in-flight!”);

// 异步请求 promoteCalls 为 true,同步请求为 false

if (promoteCalls) promoteCalls();

runningCallsCount = runningCallsCount();

idleCallback = this.idleCallback;

}

if (runningCallsCount == 0 && idleCallback != null) {

idleCallback.run();

}

}

public synchronized int runningCallsCount() {

// 返回所有正在运行的同步异步请求总数

return runningAsyncCalls.size() + runningSyncCalls.size();

}

private void promoteCalls() {

// 1.当正在运行的同步请求异步请求数大于64时直接 return

if (runningAsyncCalls.size() >= maxRequests) return; // Already running max capacity.

// 2.没有等待执行的异步请求的时候 return

if (readyAsyncCalls.isEmpty()) return; // No ready calls to promote.

// 3.可以从 readyAsyncCalls 中取任务放到 runningAsyncCalls 中并执行

for (Iterator i = readyAsyncCalls.iterator(); i.hasNext(); ) {

// 从迭代器获取下一个等待的异步任务

AsyncCall call = i.next();

// 对同一个 host 请求数不能超过 5

if (runningCallsForHost(call) < maxRequestsPerHost) {

// 从 readyAsyncCalls 中删除 call

i.remove();

// 把 call 添加到 runningAsyncCalls

runningAsyncCalls.add(call);

// 使用线程池执行 call

executorService().execute(call);

}

// 一直执行 for 循环直到 runningAsyncCalls 数达到 64 个

if (runningAsyncCalls.size() >= maxRequests) return; // Reached max capacity.

}

}

复制代码

同步请求和异步请求执行后最终都会调用 dispatcher.finish(),内部执行的区别是异步请求会调用 promoteCalls(),目的就是对 readyAsyncCalls 和 runningAsyncCalls 进行调度

2.5拦截器

拦截器代码如下:

/RealCall/

Response getResponseWithInterceptorChain() throws IOException {

// 创建一个拦截器集合

List 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));

// (1) 构建责任链

Interceptor.Chain chain = new RealInterceptorChain(interceptors, null, null, null, 0,

originalRequest, this, eventListener, client.connectTimeoutMillis(),

client.readTimeoutMillis(), client.writeTimeoutMillis());

// (2) 处理责任链中的拦截器

return chain.proceed(originalRequest);

}

最后

现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!

Android架构师之路很漫长,一起共勉吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

llis(),

client.readTimeoutMillis(), client.writeTimeoutMillis());

// (2) 处理责任链中的拦截器

return chain.proceed(originalRequest);

}

最后

现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务Curd而已!现如今市场上初级程序员泛滥,这套教程针对Android开发工程师1-6年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶Android中高级、架构师对你更是如鱼得水!

为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!

Android架构师之路很漫长,一起共勉吧!

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip204888 (备注Android)
[外链图片转存中…(img-yCzNwr1t-1713443469068)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 28
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值