OkHttp面试之--OkHttp的整个异步请求流程

通过上一节,我们已经了解了如何使用OkHttp发送异步请求,下载网络图片信息并显示到ImageView控件上,从这一节开始我们就来开始研究一下其内部的实现流程和原理。因为整个流程相对而言还是比较复杂,因此对于流程的分析我划分成以下几个章节去介绍

  1. 流程概述
  2. 拦截器的原理
  3. HttpEngine中sendRequest的流程分析
  4. HttpEngine中readResponse的流程分析

这一节我们先来看一下整个流程的概述,先上一张时序图
这里写图片描述
以上图片来自http://www.jianshu.com/p/db197279f053

就从上一些OkHttp的使用开始分析:
上一节我们通过OkHttpClient.newCall(Request)的方法创建出一个Call对象,
Call是一个接口代码如下:

package okhttp3;

import java.io.IOException;

public interface Call {

  Request request();

  Response execute() throws IOException;

  void enqueue(Callback responseCallback);

  void cancel();

  boolean isExecuted();

  boolean isCanceled();

  interface Factory {
    Call newCall(Request request);
  }
}

因此OkHttpClient需要给我们返回一个Call接口的实现类,点击去看一下,代码如下:

/**
   * Prepares the {@code request} to be executed at some point in the future.
   */
  @Override public Call newCall(Request request) {
    return new RealCall(this, request);
  }

可以发现,其实返回的是RealCall对象。

接下来在Activity中调用Call.enqueue(Callback)方法,点进去之后代码如下:
这里写图片描述
在enqueue一参的方法中又调用了2参数的方法,并将第二个参数forWebSocket置为了false.

而在2参数的enqueue方法中,我们发现最终调用了client.dispatcher.enqueue的方法,并且将Callback和forWebSocket两个参数封装到了一个叫做AsyncCall的对象当中.

这个dispatcher就是OkHttpClient中的一个全局变量,点进去查看如下:

synchronized void enqueue(AsyncCall call) {
    if (runningAsyncCalls.size() < maxRequests && runningCallsForHost(call) < maxRequestsPerHost) {
      runningAsyncCalls.add(call);
      executorService().execute(call);
    } else {
      readyAsyncCalls.add(call);
    }
  }

Dispatcher内部是过一个线程池来执行,超过最大请求数后则先加入准备请求的队列中,对于这个线程池后续会单独用一篇博客来讲解,此时我们主要来整理一下整个请求流程,因此不做过多解释。 以上代码会执行到if代码块,然后执行executorService().execute(call); 看到这对于线程池有了解的同学应该能立马想到AsyncCall其实就是一个Runnable对象,我们点进AsyncCall代码中可以看到它就是继承了NamedRunnable,而NamedRunnable又实现了Runnable接口并且在run方法中主动调用了execute的方法,如下所示:
这里写图片描述

而这个抽象的execute方法在AsyncCall中已经被实现,如下所示:

这里写图片描述

由上图可以看到,当执行一个AsyncCall的execute方法时,会调用一个叫做getResponseWithInterceptorChain的方法,并返回Response对象,然后通过接口回调的方式将此Response返回给我们在Activity中所实现的Callback接口并刷新UI。

那这个getResponseWithInterceptorChain内部又是如何工作的呢??其实这个方法中的源码很简单,如下所示:
这里写图片描述

创建了一个ApplicationInterceptorChain对象,然后调用其proceed方法进行,接下来看一下ApplicationInterceptorChain的proceed代码如下

这里写图片描述

在proceed方法中,判断如果index小于OkHttpClient中拦截器集合的个数,则会递归创建新的ApplicationInterceptorChain对象,并将这个新的ApplicationInterceptorChain对象那个传递给index下标的拦截器的intercept方法

注意:此处有一个亮点,如果我们想自己实现Intercept一定要在intercept方法中主动调用chain.proceed方法,这样整个递归循环才能顺利的执行下去,反过来说我们也可以在某一个拦截器中将网络请求进行拦截,做法就是只要在拦截器中不调用proceed方法即可

对于拦截器的作用以及原理我会在后续章节中单独分析


但是在这个递归循环中,最终index都会处于一个>=client.interceptors.size的阶段,因此最终会调用最后一行代码getResponse(request, forWebSocket)方法。这个方法是真正的发送网络请求并获取Response的方法,其内部代码如下所示:

这里写图片描述

如图所示,在getResponse方法中创建了一个HttpEngine的对象,然后分别调用HttpEngine的sendRequest和readResponse方法,这两个方法依次是发送网络请求和读取网络请求结果,最后将Response对象返回到之前说的getResponseWithInterceptorChain方法,并回传给Activity中的Callback

对于HttpEngine内部实现后续会单独再做分析。

最后用两个图来做一个流程总结

这里写图片描述


这里写图片描述

下一节我们一起来看一下HttpEngine.sendRequest方法内部是如何处理的

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
OkHttp支持异步请求,当发起异步请求时,程序是非阻塞状态,可以继续接收新的请求,响应返回时会调用一个回调处理响应数据。 在OkHttp中,异步请求是通过使用Callback来实现的。异步请求时会用到Dispatcher,它会内部指定线程池去执行异步任务,并在执行完毕之后提供了finish方法结束异步请求。然后从等待队列中获取下一个满足条件的异步任务去执行。 这个方式可以避免在请求发起到拿到响应结果之前程序一直处于阻塞状态,提高了程序的性能。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [详解Android的OkHttp包编写异步HTTP请求调用的方法](https://download.csdn.net/download/weixin_38522552/12795788)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Okhttp同步与异步请求知识介绍](https://blog.csdn.net/sinat_34241861/article/details/114307539)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值