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内部实现后续会单独再做分析。

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

时间: 2024-10-27 12:58:32

OkHttp面试之--OkHttp的整个异步请求流程的相关文章

okhttp异步请求流程和源码分析

1.创建一个OkHttpClient对象. 2.构建一个Request对象,通过OkHttpClient和Request对象,构建出Call对象. 3.执行Call的enqueue方法. 判断当前Call. 封装成一个AsyncCall对象. client.dispatcher().enqueue(). 原文地址:https://www.cnblogs.com/webor2006/p/9063363.html

普通B/S架构模式同步请求与AJAX异步请求区别(个人理解)

在上次面试的时候有被问到过AJAX同步与异步之间的概念问题,之前没有涉及到异步与同步的知识,所以特意脑补了一下,不是很全面... 同步请求流程:提交请求(POST/GET表单相似的提交操作)---服务器对请求进行处理(期间客户端浏览器不能进行其他任何操作)----处理完毕返回数据 异步请求流程:通过事件触发请求(移除/点击事件)---服务器对请求进行处理(期间客户端浏览器可以做发送其他请求,不需要管其他请求是否有处理)---处理完毕返回数据 同步就是你叫我去吃饭,我听到了就和你去吃饭:如果没有听

OkHttp面试之--HttpEngine中的sendRequest方法详解

上一节我们介绍了OkHttp网络异步请求的整个流程.其中在流程的最后阶段,我们发现最终创建了HttpEngine对象,并分别调用的此对象的sendRequest和readResponse方法.这两个方法 分别有它相应的作用.这一节我们着重来分析sendRequest流程. 以下是sendRequest的整个方法中的内容: public void sendRequest() throws RequestException, RouteException, IOException { if (cac

深入理解OkHttp源码(一)——提交请求

本篇文章主要介绍OkHttp执行同步和异步请求的大体流程.主要流程如下图: 主要分析到getResponseWidthInterceptorChain方法,该方法为具体的根据请求获取响应部分,留着后面的博客再介绍. Dispatcher类 Dispatcher类负责异步任务的请求策略.首先看它的部分定义: public final class Dispatcher { private int maxRequests = 64; private int maxRequestsPerHost = 5

Okhttp 请求流程梳理

最近在看 Okhttp 的源码.不得不说源码设计的很巧妙,从中能学到很多.其实网上关于 Okhttp 的文章已经很多了,自己也看了很多.但是俗话说得好,好记性不如烂笔头,当你动手的时候,你会发现你在看的时候没有注意到的很多细节. 本次要分析的 Okhttp 版本是 3.8.1,在 gradle 中引用如下: implementation 'com.squareup.okhttp3:okhttp:3.8.1' implementation 'com.squareup.okio:okio:1.7.0

调用enqueue执行异步请求有一个参数设置回调。

前面的内容介绍了OkHttp,本章就来教大家okhttp的基本使用,学了这些基本东西之后,大家有其他的需求可以自行扩展.以下的所有请求都是异步请求服务器,在真实的企业开发中,基本都是异步. 首先创建一个request对象,通过request设置请求url,通过这个类还可以设置更多的请求信息.然后通过Request去构造一个Call对象. 调用enqueue执行异步请求,有一个参数设置回调.请求成功或者失败会调用Callback接口的onResponse跟onFailure方法,因为这是异步请求,

学习笔记12JS异步请求

*一般用JS来监听按钮事件,都应该先监听页面OnLoad事件. *Js写在哪里,就会在页面解析到哪里执行. 异步请求:所谓异步请求,就是使用JS来监听按钮点击事件,并且发送请求,等到回复后,再使用JS来进行页面跳转,或动态改变页面.使用场合:当请求是ashx是,都可以使用异步方法,页面就无需刷到ashx的一个空白页面或者不用于展示的页面了. *使用jquery发送异步请求:$("#按钮ID").Click(fuction(){ $.get( "页面URL.ashx"

jQuery基础(Ajax,load(),getJSON(),getScript(),post(),ajax(),同步/异步请求数据)

1.使用load()方法异步请求数据 使用load()方法通过Ajax请求加载服务器中的数据,并把返回的数据放置到指定的元素中,它的调用格式为: load(url,[data],[callback]) 参数url为加载服务器地址,可选项data参数为请求时发送的数据,callback参数为数据请求成功后,执行的回调函数. 2.使用getJSON()方法异步加载JSON格式数据 使用getJSON()方法可以通过Ajax异步请求的方式,获取服务器中的数据,并对获取的数据进行解析,显示在页面中,它的

ajax 异步请求四个步骤

ajax异步请求详解 ajxa定义:异步的JavaScript和xml 1.XMLHttpRequst的出现才有了异步处理 2.创建XmlHttpRequest对象 var request=new XMLHttpRequest(); 注意:如果要兼容IE6以下浏览器则需要编写如下代码 var request; if(window.XMLRequest){ request=new XMLRequestHttpRequest();  //IE7.IE8.360等 }else{ request=new