您的位置:首页 > 理论基础 > 计算机网络

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

2018-04-01 00:27 555 查看
就同步和异步请求的方法调用来说,两者的差别不是很大。执行同步请求调用的是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()方法需要在同步代码块中执行。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: