android源码宇宙——Okhttp

简介: android源码宇宙——Okhttp

Okhttp的使用


image.png


源码


阅读大纲

  1. 同步调用网络请求流程
  2. 异步调用网络请求流程
  3. Dispatcher类的代码逻辑
  4. 几个拦截器的逻辑


查看同步调用主流程

  1. 从newCall开始

调用RealCall.newRealCall创建Call

image.png

  1. RealCall.newRealCall

image.png

  1. 因为上一步中获取到的Call类型是RealCall,下面我们看看RealCall.execute

下一步我们先看dispatcher().executed然后再看getResponseWithInterceptorChain方法

image.png

  1. dispatcher().executed方法和getResponseWithInterceptorChain方法

dispatcher().executed方法

image.png

getResponseWithInterceptorChain方法

这个方法里面先构建了一个连接器,然后执行拦截器

image.png

  1. 同步调用完成

异步调用网络请求流程

  1. 业务代码中执行异步请求

image.png

  1. RealCall.enqueue

这个方法最终又调到了Dispatcher.enqueue

image.png

  1. Dispatcher.enqueue调度异步请求AsyncCall

image.png

  1. 上面的方法如果调用了executeorService.execute就开始执行线程池了,因为我们的AsyncCall实现了NameRunnable,然后NameRunnable又实现了Runnable,所以去看NameRunnable.run方法吧

image.png

  1. AsyncCall.execute执行请求

image.png


Dispatcher类的代码逻辑

Dispatcher的作用是对请求进行分发,也就是他是用来管理Call和分发Call的。同时他还维护了一个线程池

Dispatcher内部维护了三个队列:

  • runningSyncCalls同步请求队列   - 用于执行同步请求
  • runningAsyncCalls异步请求队列  -  用于执行异步请求
  • readyAsyncCalls等待中的请求队列  -  当异步请求并发数量达到限制时将请求放到等待队列中

Dispatcher如何调度异步逻辑

Dispatcher中没有太多的复杂逻辑,主要对其中的几个重要方法进行说明一下

  1. executorService获取线程池
  2. setMaxRequests设置支持的最大请求并发数,这个主要是相对于异步请求来说的,和同步请求没关系
  3. enqueue 调度异步请求
  4. cancelAll 取消所有请求
  5. promoteCalls 决定是否将等待队列中的请求加入到异步队列中进行执行
  6. executed 执行同步请求
  7. finished 两个finish方法,分别用来结束同步请求和异步请求

拦截器链的执行逻辑和几个拦截器内部的逻辑

拦截器执行逻辑也就是getResponseWithInterceptorChain方法

  1. 构建和执行责任链

需要说明的是client.interceptors()获取的拦截器无论如何都会被调用 而client.networkInterceptors()获取的拦截器只有请求走到真实网络请求之前才会调用(如果请求使用了缓存,或者真实请求开始之前结束了则不会调用)

image.png


  1. RealInterceptorChain.proceed方法

最终这里的逻辑可以保证对责任链进行执行

image.png


RetryAndFollowUpInterceptor重试,重定向拦截器

重定向拦截器实际上就是在内部维护了一个循环。如果当前请求支持重定向,那么会在当前的责任链位置重新执行责任链(会重试多次)。还有就是,它会尝试重用之前的连接

  1. 看intercept方法

image.png

image.png

下图中sameConnection实际上就是判断了一下请求的绝对host,port,scheme是否一致

image.png


BridgeInterceptor 桥拦截器

  • 桥拦截器会从用户的请求参数中,构建请求Request。主要是是对header中的内容进行补充完善,这一点帮我们省去了很多事情(比如使用HttpUrlconnection很多header参数需要我们自己处理)。
  • 然后使用这个请求访问网络,最后使用网络返回结果构建响应

intercept方法解读

  1. 处理请求header

image.png

image.png

  1. 请求获取响应并处理响应

image.png

CacheInterceptor缓存拦截器

主要做了如下几件事
  • 如果无法网络获取请求且缓存为空返回请求失败
  • 如果无法通过网络获取请求,且有缓存直接返回缓存
  • 如果请求结果返回304,说明缓存仍然在有效期内(返回的response中没有实体内容),直接把缓存返回并且刷新缓存
  • 如果网络请求返回了实体内容,并且请求是支持缓存的,则写入缓存
intercept源码

缓存拦截器会根据请求信息来决定是否使用缓存数据,并且在请求完成后决定是否存储缓存

image.png

image.png

image.png

image.png


ConnectInterceptor连接拦截器

ConnectInterceptor用来创建或者获取缓存中的请求连接,其实就是三次握手。不过如果缓存池中有可用连接则不需要进行三次握手,这就是连接器中主要功能---节省我们的三次握手时间

简述一下获取连接的过程(读代码的时候跟着这个思路来做):

  1. 先检查StreamAllocation类中当前的connection是否可用,如果不可用则关闭它的socket
  2. 尝试从连接池中获取连接赋值给StreamAllocation.connection,如果获取成功了则直接复用
  3. 如果第2步中没有获取成功,并且请求是http2,则尝试再次使用route获取多路复用的连接
  4. 如果第三部仍然没有获取到连接,则创建一个连接并加入到缓存池中
  5. 如果连接是第4步中创建的,则需要进行三次握手连接后才能使用
  6. 如果我们第5步中连接创建完成后,发现已经有其它请求创建了连接,则我们将我们自己创建的连接干掉,然后使用其它请求创建的连接进行返回。
  7. intercept代码

image.png

  1. newStream方法

image.png

  1. findHealthyConnection循环获取可用连接

image.png

  1. 最后一步findConnection真实的获取连接的逻辑,方法非常长

findConnection会有两次尝试从连接池中获取连接,第一次是不通过route去获取。而第二次是通过route去获取。

会有第二次获取的原因是http2有了多路复用 的概念,每个连接可以有多个stream的

http2多路复用就是同一个tcp链接可以并发执行多个http请求。开发过程中我还没见过http2呢,所以这里也不用太过深究

image.png

image.png

image.png

image.png


CallServerInterceptor请求网络拦截器

intercept方法

image.png

image.png

image.png

image.png

总结


Okhttp可以使用同步和异步请求两种方式请求网络来获取数据,请求的过程都是构建请求参数,构建Call对象,然后同步或者异步获取返回数据。

同步和异步请求的方式最终都会将Call调度到Dispatcher类中,

它们的不同之处在于:

同步请求方式会把Call加入到同步请求队列中然后执行请求。

而异步请求会可能会把请求放到正在执行中的异步请求队列中,也可能加入到异步请求准备队列中。如果我们当前正在执行的异步请求数量大于最大并发数,则会把请求加入到准备队列中。每一个异步请求执行完成后都会尝试把准备队列中的请求加入到正在执行的队列中。

需要说明的是异步请求使用线程池执行

两种方式最终都会调用getResponseWithInterceptorChain拿到最终的数据。

getResponseWithInterceptorChain里面维护了一个责任链。这个责任链里面有多个连接器,包括1重试拦截器、2桥拦截器、3缓存拦截器、4连接拦截器、5网络请求拦截器。我们的请求参数会经过这些拦截器的处理,过程就是从1->5,返回Response结果的时候会再从5->1。

实际上还包括自定义拦截器

后面的过程就是将数据返回给调用处了,同步请求直接返回结果,异步请求使用回调的方法回调结果。

拦截器RealInterceptorChain为什么不使用遍历的方式执行

  1. 遍历的方式不容易处理中断和异常的情况
  2. 我们的责任链执行有两个方向,正向执行的时候将请求参数向前传递处理。反向的时候将response回传。这一点遍历的方式是做不到的
  3. 重试的机制,比如我们的责任链每向前一次都会new一个RealInterceptorChain,这样如果第一次执行后发现请求失败了,我们想重试就会重新从RetryAndFollowUpInterceptor位置new一个RealInterceptorChain进行第二次执行。这样第一次请求新建的几个责任链单元的缓存数据不会影响我们第二次执行。如果使用遍历的方式就不可能达到这个效果。

例如当你使用遍历的方式实现责任链,想重试的时候当请求走得到CacheInterceptor,发现CacheInterceptor中包含了我们上一次执行的逻辑残留,他就需要处理付出更多的逻辑处理这种逻辑残留,无形中增加了工作量。



相关文章
|
6月前
|
开发工具 Android开发 git
全志H713 Android 11 :给AOSP源码,新增一个Product
本文介绍了在全志H713 Android 11平台上新增名为myboard的产品的步骤,包括创建新的device目录、编辑配置文件、新增内核配置、记录差异列表以及编译kernel和Android系统的详细过程。
398 0
|
6月前
|
开发工具 uml git
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
本文分享了下载AOSP源码的方法,包括如何使用repo工具和处理常见的repo sync错误,以及配置Python环境以确保顺利同步特定版本的AOSP代码。
860 0
AOSP源码下载方法,解决repo sync错误:android-13.0.0_r82
|
6月前
|
Java Android开发 芯片
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
本文介绍了如何将基于全志H713芯片的AOSP Android源码导入Android Studio以解决编译和编码问题,通过操作步骤的详细说明,展示了在Android Studio中利用代码提示和补全功能快速定位并修复编译错误的方法。
351 0
使用Android Studio导入Android源码:基于全志H713 AOSP,方便解决编译、编码问题
|
6月前
|
Ubuntu 开发工具 Android开发
Repo下载、编译AOSP源码:基于Ubuntu 21.04,android-12.1.0_r27
文章记录了作者在Ubuntu 21.04服务器上配置环境、下载并编译基于Android 12.1.0_r27版本的AOSP源码的过程,包括解决编译过程中遇到的问题和错误处理方法。
371 0
|
6月前
|
开发工具 git 索引
repo sync 更新源码 android-12.0.0_r34, fatal: 不能重置索引文件至版本 ‘v2.27^0‘。
本文描述了在更新AOSP 12源码时遇到的repo同步错误,并提供了通过手动git pull更新repo工具来解决这一问题的方法。
224 1
|
6月前
|
Ubuntu 开发工具 Android开发
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
本文介绍了在基于Ubuntu 22.04的环境下配置Python 3.9、安装repo工具、下载和同步AOSP源码包以及处理repo同步错误的详细步骤。
394 0
Repo下载AOSP源码:基于ubuntu22.04 环境配置,android-12.0.0_r32
|
6月前
|
Android开发
我的Android 进阶修炼(1): AOSP源码根目录结构
本文介绍了AOSP源码的根目录结构,提供了基于MTK9269 Android 9.0源码的目录说明,帮助读者了解AOSP源码的组织方式和各目录的功能。
311 0
我的Android 进阶修炼(1): AOSP源码根目录结构
|
6月前
|
Android开发 Docker 容器
docker中编译android aosp源码,出现Build sandboxing disabled due to nsjail error
在使用Docker编译Android AOSP源码时,如果遇到"Build sandboxing disabled due to nsjail error"的错误,可以通过在docker run命令中添加`--privileged`参数来解决权限不足的问题。
1236 1
|
6月前
|
API 开发工具 Android开发
Android源码下载
Android源码下载
710 0
|
7月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的高校后勤网上报修系统安卓app附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的高校后勤网上报修系统安卓app附带文章源码部署视频讲解等
78 0

热门文章

最新文章

  • 1
    如何修复 Android 和 Windows 不支持视频编解码器的问题?
  • 2
    Android历史版本与APK文件结构
  • 3
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 4
    【04】flutter补打包流程的签名过程-APP安卓调试配置-结构化项目目录-完善注册相关页面-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程
  • 5
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
  • 6
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
  • 8
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
  • 9
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
  • 10
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
  • 1
    Cellebrite UFED 4PC 7.71 (Windows) - Android 和 iOS 移动设备取证软件
    24
  • 2
    【03】仿站技术之python技术,看完学会再也不用去购买收费工具了-修改整体页面做好安卓下载发给客户-并且开始提交网站公安备案-作为APP下载落地页文娱产品一定要备案-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    33
  • 3
    Android历史版本与APK文件结构
    121
  • 4
    【02】仿站技术之python技术,看完学会再也不用去购买收费工具了-本次找了小影-感觉页面很好看-本次是爬取vue需要用到Puppeteer库用node.js扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-优雅草卓伊凡
    29
  • 5
    【01】仿站技术之python技术,看完学会再也不用去购买收费工具了-用python扒一个app下载落地页-包括安卓android下载(简单)-ios苹果plist下载(稍微麻烦一丢丢)-客户的麻将软件需要下载落地页并且要做搜索引擎推广-本文用python语言快速开发爬取落地页下载-优雅草卓伊凡
    23
  • 6
    APP-国内主流安卓商店-应用市场-鸿蒙商店上架之必备前提·全国公安安全信息评估报告如何申请-需要安全评估报告的资料是哪些-优雅草卓伊凡全程操作
    57
  • 7
    【09】flutter首页进行了完善-采用android studio 进行真机调试开发-增加了直播间列表和短视频人物列表-增加了用户中心-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    37
  • 8
    当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
    73
  • 9
    【08】flutter完成屏幕适配-重建Android,增加GetX路由,屏幕适配,基础导航栏-多版本SDK以及gradle造成的关于fvm的使用(flutter version manage)-卓伊凡换人优雅草Alex-开发完整的社交APP-前端客户端开发+数据联调|以优雅草商业项目为例做开发-flutter开发-全流程-商业应用级实战开发-优雅草Alex
    119
  • 10
    Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
    29