当前位置: 首页 > news >正文

Android---OkHttp详解

OkHttp 是一套处理 HTTP 网络请求的依赖库,由 Square 公司设计研发并开源,目前可以在 Java 和 Kotlin 中使用。对于 Android App,OkHttp 现在几乎已经占据了所有的网络请求操作。RetroFit + OkHttp 实现网络请求似乎成了一种标配。

因此,它也是每个 Android 开发工程师的必备技能。了解其内部实现原理,可以更好的进行功能扩展、封装以及优化。因为是 Http 网络请求的依赖库,所有需要有一定的网络知识基础。

网络请求流程分析

OkHttp 经过几次迭代后,发生了很多变化:

\bullet 更好的 WebSocke 支持;

\bullet 更好的 Interceptor 责任链;

\bullet 最核心的 HttpEngine 也变成了 HttpCodec。

OkHttp的基本使用

OkHttpClient client = new OkHttpClient();Request request = new Request.Builder().url(url).build();client.newCall(request).enqueue(new Callback(){@Overridepublic void onFailure(Call call, IOException e){}@Overridepublic void onResponse(Call call, Response response) throw IOException{}
});

除了直接 new OkHttpClient() 之外,还可以使用内部工厂类 Builder 来设置 OkHttpClient。如下所示

OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(60, TimeUnit.SECONDS) // 设置超时.addInterceptor(interceptor) // 添加拦截器.proxy(proxy) // 设置请求代理.cache(cache); // 设置缓存策略
OkHttpClient client = builder.build();

请求操作的起点从 OkHttpClient.newCall().enqueue() 方法开始

newCall():这个方法会返回一个 RealCall 类型对象。通过它将网络请求操作添加到网络请求队列中去。

RealCall.enqueue():调用 dispatcher 的入队方法,执行一个网络请求操作。

可以看出,最终的请求操作是委托给 dispatcher 的 enqueue() 方法内实现的。

Dispatcher 是 OkHttpClient 的调度器,是一种门户模式。主要用来实现执行、取消异步请求操作,本质上是内部维护了一个线程池去执行异步操作。并且,在 Dispatcher 内部根据一定的策略,保证最大并发个数、同一 host 主机允许执行请求的线程个数。

Dispatcher 的 enqueue() 方法具体实现,如下

可以看出,实际上就是使用线程池执行了一个 AsyncCall,而 AsyncCall 实现了 Runnable 接口。因此整个操作会在一个子线程中执行。AsyncCall 中的 run() 方法如下

在 run() 方法中执行了另一个 execute() 方法。而真正获取请求结果的方法是在 getResponseWithInterceptorChain() 方法中。其内部是一个拦截器的调用链。具体代码如下

每一个拦截器的作用

\bullet BridgeInterceptor:主要对 Request 中的 Head 设置默认值。比如 Content-Type、Keep-Alive、Cookie 等。

\bullet CacheInterceptor:负责 HTTP 请求的缓存处理。

\bullet ConnectInterceptor:负责建立与服务器地址之间的连接,也就是 TCP 链接。

\bullet CallServerInterceptor:负责向服务器发送请求,并从服务器拿到远端数据结果。

在添加上述几个拦截器之前,会调用 client.interceptors,将开发人员设置的拦截器添加到列表当中。对于 Request Head 以及 TCP 链接,我们能控制修改的成分不说很多,所以我们重点分析的是 CacheInterceptor 和 CallServerInterceptor。

1. CacheInterceptor 缓存拦截器

CacheInterceptor 主要做以下几件事情:

a. 根据 Request 获取当前已有缓存的 Response(有可能为 null),并根据获取到的缓存 Response,创建 CacheStrategy 对象。

b. 通过 CacheStrategy 判断当前缓存中的 Response 是否有效(比如是否过期)。

如果缓存 Response 可用,则直接返回。否则调用 chain.proceed() 继续执行下一个拦截器。也就是发送网络请求,从服务器获取远端 Response,具体如下

c. 如果从服务器端成功获取 Response,再判断是否将此 Response 进行缓存操作。代码如下

通过 Cache 实现缓存功能

通过上面分析缓存拦截器的流程可以看出,OkHttp 只是规范了一套策略,但是具体使用何种方式将数据缓存到本地,以及如何从本地缓存中取出数据,都是由开发人员自己定义并实现,并通过 OkHttpClient.Builder 的 cache 方法设置。

OkHttp 提供了一个默认的缓存类 Cache.java,可以在构建 OkHttpClient 时,直接使用 Cache 来实现缓存功能。只需要指定缓存路径以及最大可用空间即可。如下所示

上述代码使用 Android app 内置目录 cache 目录作为缓存路径,并设置缓存最大可用空间为 20M。

实际上,在 Cache 内部使用了 DiskLruCache 实现具体的缓存功能。如下所示

DiskLruCache 最终会以

2. CallServerInterceptor 拦截器

CallServerInterceptor 是 OkHttp 最后一个拦截器,也是 OkHttp 中最核心的网络请求部分。它的 Intercept 方法如下

如上图所示,主要分为两部分。蓝线以上的操作是向服务器端发送请求数据,蓝线以下代表从服务器端获取请求结果并构建 response 对象

OkHttp 使用扩展

仔细观察上面的代码,在 CallServerInterceptor 中的 Intercept 方法。可用发现,在向服务的发送数据和获取数据都是使用一个 Okio 的框架。

Okio 是 Square 公司打造的另外一个轻量级 IO 库,它是 OkHttp 框架的基石。在构建 Response 时,需要调动 body() 方法传入一个 ResponseBody 对象,ResponseBody 内部封装了对请求结果的流读取操作。可用通过继承并扩展 ResponseBody 的方式获取网络请求的进度。

a. 继承 ResponseBody

其中,progressListener 是一个自定义的进度监听器,通过它向上层汇报网络请求进度。

b. 自定义 progressBarClient

getClient 可以根据项目的不同添加其他共通设置,比如 timeout 时间,DNS、Log日志 interceptor 等。

getProgressBarClient 通过添加一个拦截器,并且在 intercept 方法中将自定义的 ProgressResponseBody 传个 body 方法。当通过 getProgressBarClient 发送网络请求时,OkHttpClient 从服务端获取到数据之后,会不断调用 ProgressResponseBody 中的 source 方法。然后通过 progressListener 向上层通知请求进度的结果。

c. 实践拓展-Picasso

我们可以将上面实现的 ProgressBarClient 用于 Square 公司另一个请求库--Picasso。Picasso 是 Square 公司研发用来从网络端获取图片数据的依赖库,内部实质上是使用 OkHttp 来实现请求操作的。因此我们可以将 ProgressBarClient 替换 OkHttpClient,这样就能获取下载图片的进度。代码如下

 后续只要通过 GetPicasso 方法即可获得一个自带下载进度的 Picasso 对象。因为,OkHttp、Picasso 和 Okio 都来自 Square 公司。

总结

主要分析了 OkHttp 的源码实现:

\bullet OkHttp 内部是一个门户模式,所有的下发工作都是通过一个门户 Dispatcher 来进行分发。

\bullet 在网络请求阶段通过责任链模式,链式的调用各个拦截器的 intercept 方法。重点介绍了2个比较重要的拦截器:CacheInterceptorCallServerInterceptor。它们分别用来做请求缓存执行网络请求操作。

\bullet 在理解源码实现的基础上,对 OkHttp 的功能进行了一些扩展,实现了网络请求进度的实现。

相关文章:

Android---OkHttp详解

OkHttp 是一套处理 HTTP 网络请求的依赖库,由 Square 公司设计研发并开源,目前可以在 Java 和 Kotlin 中使用。对于 Android App,OkHttp 现在几乎已经占据了所有的网络请求操作。RetroFit OkHttp 实现网络请求似乎成了一种标配。 因此&…...

向某文件中逐秒追加带序号输入当前时间 fgets fputs fprintf sprintf

//向某文件中逐秒追加带序号输入当前时间 #include<stdio.h> #include<stdlib.h> #include<time.h> #include<string.h> #include <unistd.h> int main(int argc, char const *argv[]) { time_t tv; // time(&tv);//法1:获取秒数 …...

同为科技(TOWE)机架PDU产品在IDC数据中心机房建设中的应用

当今社会互联网发展迅速&#xff0c; 随着带宽需求的提升&#xff0c; 网络的保密性、安全性的要求就越来越迫切。PDU(Power Distribution Unit) 是 PDU具备电源分配和管理功能的电源分配管理器。PDU电源插座是多有设备运行的第一道也是最为密切的部件&#xff0c; PDU的好坏直…...

Elasticsearch学习笔记

1.核心概念 bucket: 一个数据分组&#xff08;类似于sql group by以后的数据&#xff09;metric&#xff1a;对bucket执行的某种聚合分析的操作&#xff0c;比如说求平均值&#xff0c;最大值&#xff0c;最小值。一些系列的统计方法(类似 select count(1) MAX MIN AVG) 请…...

Java框架随笔

Maven面试题 Myabtis面试题 文章目录 Maven面试题Myabtis面试题 1、简述Spring Boot的启动流程2、如何理解Bean的生命周期3、MyBatis的主要功能4、MyBatis的组成部分5、MyBatis的动态SQL 1、简述Spring Boot的启动流程 Spring Boot的启动流程可以分为以下几个步骤&#xff1a…...

自然语言处理基础——词表示

词表示 把自然语言中最基本的语言单元——词转换为机器能够理解的 词表示能完成以下两个能力 词相似度计算 词与词之间语义的关系 近义词&上位词 使用近义词或上位词表示的问题 遗漏差异 遗漏新的释义 带有主观性 数据吸收 需要大量人工构建 One-Hot Representation …...

2023年9月青少年软件编程(C 语言) 等级考试试卷(七级)

青少年软件编程&#xff08;C/C&#xff09;7级等级考试真题试卷&#xff08;2023年9月&#xff09; 编程题第 1 题 红与黑&#xff08;2023.9&#xff09; 有一间长方形的房子&#xff0c;地上铺了红色、黑色两种颜色的正方形瓷砖。你站在其中一块黑色的瓷砖上&#xff0c…...

鸿鹄工程项目管理系统 Spring Cloud+Spring Boot+Mybatis+Vue+ElementUI+前后端分离构建工程项目管理系统项目背景

鸿鹄工程项目管理系统 Spring CloudSpring BootMybatisVueElementUI前后端分离构建工程项目管理系统 1. 项目背景 一、随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大。为了提高工程管理效率、减轻劳动强度、提高信息处理速度和准确性&#xff0c;公司对内部工程管…...

apache httpd 换行解析漏洞

原理 Apache HTTPD是一款HTTP服务器&#xff0c;它可以通过mod_php来运行PHP网页。其2.4.0~2.4.29版本中存在一个解析漏洞&#xff0c;在解析PHP时&#xff0c;1.php\x0A将被按照PHP后缀进行解析&#xff0c;导致绕过一些服务器的安全策略。 漏洞编号 cve-2017-15715 环境…...

【设计模式】工厂模式

工厂模式 1.什么是工厂模式 它提供了一种创建对象的最佳方式。在工厂模式中&#xff0c;我们在创建对象时不会对客户端暴露创建逻辑&#xff0c;并且是通过使用一个共同的接口来指向新创建的对象。实现了创建者和调用者分离&#xff0c;工厂模式分为简单工厂、工厂方法、抽象…...

C++二分算法的应用:寻找峰值原理、源码及测试用例

说明 此文是课程https://edu.csdn.net/course/detail/38771 的讲义。 源码下载&#xff1a;https://download.csdn.net/download/he_zhidan/88458478 题目 长度为n的数组nums&#xff0c;请返回任意一峰值的索引。符合以下条件之一i便是峰值的索引。 n等于1 i等于0 n>…...

外汇天眼:本周无牌裸奔平台名单出炉,你踩“坑”了么?!!

监管信息早知道&#xff01;外汇天眼将每周定期公布监管牌照状态发生变化的交易商&#xff0c;以供投资者参考&#xff0c;规避投资风险。如果平台天眼评分过高&#xff0c;建议投资者谨慎选择&#xff0c;因为在外汇天眼评分高不代表平台没问题&#xff01; 以下是监管牌照发生…...

10 读写锁ReentrantReadWriteLock

1 介绍 为什么要使用读写锁&#xff1f; 需要高并发读取和较低并发写入的应用程序&#xff0c;降低锁的粒度&#xff0c;提高系统性能 使用场景&#xff1a; 读多写少的共享资源 缓存管理&#xff1a;读 >> 写&#xff0c;控制多个线程同时读缓存&#xff0c;需要刷新o…...

laravel队列

laravel redis队列 1、创建job队列任务 php artisan make:job StoreUser执行上述命令后&#xff0c;会生成app/Jobs/StoreUser.php文件&#xff0c;编辑文件内容如下&#xff1a; <?phpnamespace App\Jobs;use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queu…...

【计算机网络】TCP 协议的相关特性

TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、基于字节流的协议。以下是TCP协议的相关特性&#xff1a; 可靠性&#xff1a;TCP通过确认和重传机制保证数据的可靠传输。 面向连接&#xff1a;TCP在传输数据前需要先建立连接。连接的建立过程包括三次握手…...

[软件安装] tmux安装及相关事项

tmux安装及相关事项 tmux是一个终端复用工具&#xff0c;可以在单个终端窗口中同时运行多个终端会话。安装tmux可以提高工作效率&#xff0c;使命令行操作更加方便。 1. 安装tmux&#xff1a; 在Linux系统下&#xff0c;可以使用包管理器来安装tmux&#xff0c;比如在Ubuntu…...

leetcode 887 ——扔鸡蛋

题目大意&#xff1a; 你有k个鸡蛋&#xff0c;对n层楼的建筑&#xff0c;请确认在f层扔鸡蛋鸡蛋恰好不会破碎的最少次数&#xff08;f满足 0 < f < n&#xff09;。 方法一&#xff1a; 状态&#xff1a;即会发生变化的量&#xff0c;很明显有两个&#xff0c;当前拥有…...

自动化运维ansible(role)

一、role的介绍 1、Roles称为角色&#xff0c;本质上是为简化playbook配置文件而产生的一种特殊的方法。 2、简单来说&#xff0c;roles就是将原本在一个yaml中的文件进行规则化分散&#xff0c;封装到不同的目录下&#xff0c;从而简化playbook的yaml配置文件大小。从其实现方…...

linux命令笔记

创建文件夹 sudo mkdir 文件夹名vim笔记 vim的查找和退出查找 进入vim 按/ 输入内容即可查找 按enter结束查找vim创建文件并在里面写东西 比如创建文件为 hello.cpp vim hello.cpp查看所有文件 # 查看所有文件&#xff0c;并以列表的形式查看&#xff0c;显示出文件大小 …...

2.3.C++项目:网络版五子棋对战之实用工具类模块的设计

文章目录 一、实用工具类模块&#xff08;一&#xff09;功能 二、设计和封装&#xff08;一&#xff09;日志宏封装&#xff08;二&#xff09;mysql_util封装&#xff08;三&#xff09;Jsoncpp-API封装&#xff08;四&#xff09;file_util封装&#xff08;五&#xff09;st…...

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …...

智慧医疗能源事业线深度画像分析(上)

引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...

基于服务器使用 apt 安装、配置 Nginx

&#x1f9fe; 一、查看可安装的 Nginx 版本 首先&#xff0c;你可以运行以下命令查看可用版本&#xff1a; apt-cache madison nginx-core输出示例&#xff1a; nginx-core | 1.18.0-6ubuntu14.6 | http://archive.ubuntu.com/ubuntu focal-updates/main amd64 Packages ng…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

uniapp中使用aixos 报错

问题&#xff1a; 在uniapp中使用aixos&#xff0c;运行后报如下错误&#xff1a; AxiosError: There is no suitable adapter to dispatch the request since : - adapter xhr is not supported by the environment - adapter http is not available in the build 解决方案&…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

Device Mapper 机制

Device Mapper 机制详解 Device Mapper&#xff08;简称 DM&#xff09;是 Linux 内核中的一套通用块设备映射框架&#xff0c;为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程&#xff0c;并配以详细的…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

Spring是如何解决Bean的循环依赖:三级缓存机制

1、什么是 Bean 的循环依赖 在 Spring框架中,Bean 的循环依赖是指多个 Bean 之间‌互相持有对方引用‌,形成闭环依赖关系的现象。 多个 Bean 的依赖关系构成环形链路,例如: 双向依赖:Bean A 依赖 Bean B,同时 Bean B 也依赖 Bean A(A↔B)。链条循环: Bean A → Bean…...

【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案

目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后&#xff0c;迭代器会失效&#xff0c;因为顺序迭代器在内存中是连续存储的&#xff0c;元素删除后&#xff0c;后续元素会前移。 但一些场景中&#xff0c;我们又需要在执行删除操作…...