【Android okhttp源码解析 三】异步请求流程和源码分析

>okhttp源码解析系列文章: >第一篇:《okhttp框架简单介绍》 >https://blog.csdn.net/colinandroid/article/details/79774907 >第二篇:《同步请求流程和源码分析》 >https://blog.csdn.net/colinandroid/article/details/79774918 >第三篇:《异步请求流程和源码分析》 >https://blog.csdn.net/colinandroid/article/details/79774932 >第四篇:《任务调度核心类dispatcher解析》 >https://blog.csdn.net/colinandroid/article/details/79774936 >第五篇:《拦截器流程和源码解析》 >https://blog.csdn.net/colinandroid/article/details/79706161

就同步和异步请求的方法调用来说,两者的差别不是很大。执行同步请求调用的是execute()方法,执行异步请求调用的是enqueue()方法,而它们两者的内部实现原理还是有很大差别的。
经过对同步请求的分析,我们已经对okhttp网络请求的方法执行很熟悉了,并且前两步都是一样的,我们这里再简单介绍一下。
第一步,创建okHttpClient对象和Request对象;第二步,创建Call对象;第三步,执行enqueue()方法。
####1. 我们来看看enqueue()方法都做了什么
这里写图片描述
这里把传进来的responseCallback对象封装成AsyncCall,然后作为参数传给okhttpclient的dispatcher对象的enqueue()方法。
这个AsyncCall又是什么呢?
这里写图片描述
我们看到AsyncCall继承自NamedRunnable,而NameRunnable实现了Runnable接口,所以这里就是把responseCallback传进Runnable中。
接着,调用okhttpclient的分发器类dispatcher的enqueue()方法。
这里写图片描述
这里首先会判断runningAsyncCalls队列的长度是否小于允许的最大请求数maxRequests,以及我们主机的最大请求数是否小于我们设定的值。
如果满足这个条件,我们就把AsyncCall对象放到runningAsyncCalls队列中,然后再通过一个线程池来执行这个异步请求。
总结一下enqueue()方法执行的流程
######1. 判断当前Call是否执行过
######2. 封装AsyncCall对象
######3. 调用dispatcher的enqueue()方法
####2.executeService().execute()执行流程
这里写图片描述
可以看到executeService()方法创建了一个线程池。我们来看下线程池的参数,第一个参数代表了核心线程的数量,这里设定为0。为什么要设定为0呢?这代表这空闲一段时间后,就会把所有线程全部销毁;第二个参数代表允许最多线程个数,这里设定为无限大,那当线程个数过多时会不会引起程序崩溃呢?我们前文提到,okhttpclient允许的最大请求是64个,它限制了okhttpclient整个异步请求数最大为64个;第三个参数代表当多余线程数大于核心线程数时,空闲的线程最多可以存活60s。
那么为什么这样设定参数呢?在我们实际运行当中可能开启20个并发请求,那么线程池因此也会创建20个线程,当工作完成后线程池就会在60s后相继消除空闲的线程。
我们接着看,这一步其实就是调用线程池的execute()方法,来执行AsyncCall的run()方法。
####3. 我们来看看AsyncCall的run()方法是如何实现的
这里写图片描述
我们在AsyncCall中没有找到run()方法,所以我们去它的父类NamedRunnable中去找,我们看到它其实就是做了一层封装,最后调用的是execute()方法。我们来看看AsyncCall的execute()方法。
这里写图片描述
这里调用getResponseWithInterceptorChain()方法,通过拦截器链过滤最终得到Response对象。该方法是okhttp设计的非常精妙的一点。
Call执行完成后会从runningAsyncCalls中移除这个线程,只有这样readyAsyncCalls中的线程才能被执行。那么问题来了,我们什么时候开始去移除这个线程呢?
在finally中我们看到调用了okhttpclient的dispatcher的finish()方法。
这里写图片描述
finish()方法主要做了以下几件事:
######1. 把请求从异步请求队列中删除
######2. promiteCalls()方法执行
######3. 如果异步请求队列为空了,则回调idleCallback()方法
可以看到异步请求的finish()方法只比同步请求的finish()方法多了一步promoteCalls()方法的执行,它其实是用来调整我们的任务队列的。我们知道异步请求需要的两个队列都是现场不安全的,所以调用promoteCalls()方法需要在同步代码块中执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值