android的网络请求框架很多,但是自android4.4之后系统内置了okhttp,可见okhttp的分量之重!这篇文章以okttp3.8.1的源码,简单解析一下okhttp的运作流程:
首先发起一个简单的异步请求,代码如下
其基本步骤就是创建OkHttpClient、Request和Call,最后调用Call的enqueue()方法。但是每次这么写很麻烦,肯定是要进行封装的。需要注意的是onResponse回调并非在UI线程。如果想要调用同步GET请求,可以调用Call的execute方法。
当调用client的newcall方法时,实际上是创建了一个RealCall对象:
当我们调用call的异步方法enqueue的方法进行网络请求的时候,实际上是调用的RealCall对象的enqueue方法
可以看到这一行 client.dispatcher().enqueue(new AsyncCall(responseCallback));最终的请求是dispatcher来完成的
看看这个Dispatcher,他主要是要维护了如下的变量来控制并发的请求任务:
当调用realcall的enqueue的方法时,最终会由dispatcher来调用自身的enqueue,看看dispatcher内的该方法实现:
当正在运行的异步请求队列中的数量小于64并且正在运行的请求主机数小于5时,把请求加载到runningAsyncCalls中并在线程池中执行,否则就加入到readyAsyncCalls中进行缓存等待。
看一下这个AsyncCall,它是RealCall的内部类,其内部也实现了execute()方法
AsyncCall有一行关键的代码需要我们注意一下:Response response = getResponseWithInterceptorChain():
可以看到在这个方法中体现了okhttp最核心的功能:拦截器。在调用chain.proceed之前会设置所有的拦截器,包括okhttp自带的和用户自己设置的拦截器
这里有5个okhttp自带的拦截器:
- RetryAndFollowUpInterceptor
在网络请求失败后进行重试
当服务器返回当前请求需要进行重定向时直接发起新的请求,并在条件允许情况下复用当前连 接 - BridgeInteceptor
设置内容长度,内容编码
设置gzip压缩,并在接收到内容后进行解压。省去了应用层处理数据解压的麻烦
添加cookie
设置其他报头,如User-Agent,Host,Keep-alive等。其中Keep-Alive是实现多路复用的必要步骤 - CacheInterceptor
当网络请求有符合要求的Cache时直接返回Cache
当服务器返回内容有改变时更新当前cache
如果当前cache失效,删除 - ConnectInterceptor
为当前请求找到合适的连接,可能复用已有连接也可能是重新创建的连接,返回的连接由连接池负责决定。 - CallServerInterceptor
负责向服务器发起真正的访问请求,并在接收到服务器返回后读取响应返回。
再看一下这个RealInterceptorChain的proceed方法:
proceed方法每次从拦截器列表中取出拦截器。当存在多个拦截器时都会在上面代码
Response response = interceptor.intercept(next);
处阻塞,并等待下一个拦截器的调用返回。
所以一次请求在所有拦截器的总体执行流程如下:
拦截器是一种能够监控、重写、重试调用的机制。通常情况下,拦截器用来添加、移除、转换请求和响应的头部信息。比如将域名替换为IP地址,在请求头中添加host属性;也可以添加我们应用中的一些公共参数,比如设备id、版本号,等等。