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

Kotlin 中 OkHttp 使用及解析

build.gradle

dependencies {//OkHttpimplementation 'com.squareup.okhttp3:okhttp:4.9.0'
}

简单使用例子

            val okHttpClient = OkHttpClient.Builder().connectTimeout(Duration.ofSeconds(10)).readTimeout(Duration.ofSeconds(10)).writeTimeout(Duration.ofSeconds(10)).retryOnConnectionFailure(true).build()val request = Request.Builder().url(url).build()val call = okHttpClient.newCall(request)call.enqueue(object : Callback {override fun onFailure(call: Call, e: IOException) {Log.e("TAG", "onFailure:${e.message}")}override fun onResponse(call: Call, response: Response) {Log.d("TAG", "onResponse: ${response.body?.string()}")}})

1、通过 Builder 模式得到  okHttpClient ,OkHttpClient 包含了对网络请求的全局配置信息,包括链接超时时间、读写超时时间、链接失败重试等配置。

2、通过 Builder 模式得到 request ,Request 包含了本次网络请求的所有请求参数,包括 url、method、headers、body 等。

3、通过 newCall 方法得到 call,Call 就是用于发起请求,可用于执行 同步请求(execute)、异步请求(enqueue)、取消请求(cancel)等各种操作。

4、调用 enqueue 方法发起异步请求返回 response ,Response 就包含了此次网络请求的所有返回信息。

5、拿到 Response 对象的 body 并以字符串流的方式进行读取。

一、OkHttpClient

OkHttpClient 使用 Builder模式来完成初始化,其提供了很多配置参数,每个选项都有默认值。

  class Builder constructor() {internal var dispatcher: Dispatcher = Dispatcher()internal var connectionPool: ConnectionPool = ConnectionPool()internal val interceptors: MutableList<Interceptor> = mutableListOf()internal val networkInterceptors: MutableList<Interceptor> = mutableListOf()internal var eventListenerFactory: EventListener.Factory = EventListener.NONE.asFactory()internal var retryOnConnectionFailure = trueinternal var authenticator: Authenticator = Authenticator.NONEinternal var followRedirects = trueinternal var followSslRedirects = trueinternal var cookieJar: CookieJar = CookieJar.NO_COOKIESinternal var cache: Cache? = nullinternal var dns: Dns = Dns.SYSTEMinternal var proxy: Proxy? = nullinternal var proxySelector: ProxySelector? = nullinternal var proxyAuthenticator: Authenticator = Authenticator.NONEinternal var socketFactory: SocketFactory = SocketFactory.getDefault()internal var sslSocketFactoryOrNull: SSLSocketFactory? = nullinternal var x509TrustManagerOrNull: X509TrustManager? = nullinternal var connectionSpecs: List<ConnectionSpec> = DEFAULT_CONNECTION_SPECSinternal var protocols: List<Protocol> = DEFAULT_PROTOCOLSinternal var hostnameVerifier: HostnameVerifier = OkHostnameVerifierinternal var certificatePinner: CertificatePinner = CertificatePinner.DEFAULTinternal var certificateChainCleaner: CertificateChainCleaner? = nullinternal var callTimeout = 0internal var connectTimeout = 10_000internal var readTimeout = 10_000internal var writeTimeout = 10_000internal var pingInterval = 0internal var minWebSocketMessageToCompress = RealWebSocket.DEFAULT_MINIMUM_DEFLATE_SIZEinternal var routeDatabase: RouteDatabase? = null
}

二、Request 

Request 包含了网络请求时的所有请求参数,一共包含以下五个。

  open class Builder {internal var url: HttpUrl? = nullinternal var method: Stringinternal var headers: Headers.Builderinternal var body: RequestBody? = null/** A mutable map of tags, or an immutable empty map if we don't have any. */internal var tags: MutableMap<Class<*>, Any> = mutableMapOf()
}

三、Call 

当调用 okHttpClient.newCall(request)   时就会得到一个 call 对象。

  /** Prepares the [request] to be executed at some point in the future. */override fun newCall(request: Request): Call = RealCall(this, request, forWebSocket = false)

 call 是一个接口,我们可以将其看做是网络请求的启动器,可用于同步请求异步请求,但重复发起多次请求的话会抛出异常。

interface Call : Cloneable {/** Returns the original request that initiated this call. */fun request(): Request/*** Invokes the request immediately, and blocks until the response can be processed or is in error.** To avoid leaking resources callers should close the [Response] which in turn will close the* underlying [ResponseBody].** ```* // ensure the response (and underlying response body) is closed* try (Response response = client.newCall(request).execute()) {*   ...* }* ```** The caller may read the response body with the response's [Response.body] method. To avoid* leaking resources callers must [close the response body][ResponseBody] or the response.** Note that transport-layer success (receiving a HTTP response code, headers and body) does not* necessarily indicate application-layer success: `response` may still indicate an unhappy HTTP* response code like 404 or 500.** @throws IOException if the request could not be executed due to cancellation, a connectivity*     problem or timeout. Because networks can fail during an exchange, it is possible that the*     remote server accepted the request before the failure.* @throws IllegalStateException when the call has already been executed.*/@Throws(IOException::class)fun execute(): Response/*** Schedules the request to be executed at some point in the future.** The [dispatcher][OkHttpClient.dispatcher] defines when the request will run: usually* immediately unless there are several other requests currently being executed.** This client will later call back `responseCallback` with either an HTTP response or a failure* exception.** @throws IllegalStateException when the call has already been executed.*/fun enqueue(responseCallback: Callback)/** Cancels the request, if possible. Requests that are already complete cannot be canceled. */fun cancel()/*** Returns true if this call has been either [executed][execute] or [enqueued][enqueue]. It is an* error to execute a call more than once.*/fun isExecuted(): Booleanfun isCanceled(): Boolean/*** Returns a timeout that spans the entire call: resolving DNS, connecting, writing the request* body, server processing, and reading the response body. If the call requires redirects or* retries all must complete within one timeout period.** Configure the client's default timeout with [OkHttpClient.Builder.callTimeout].*/fun timeout(): Timeout/*** Create a new, identical call to this one which can be enqueued or executed even if this call* has already been.*/public override fun clone(): Callfun interface Factory {fun newCall(request: Request): Call}
}

 ReallCall 是 Call 接口的唯一实现类

当调用 execute 方法发起同步请求时,

1、判断是否重复请求。

2、时间记录。

3、将自身加入到 dispatcher 中,并在请求结束时从 dispatcher 中移除自身。

4、通过 getResponseWithInterceptorChain 方法得到  response 对象。

override fun execute(): Response {check(executed.compareAndSet(false, true)) { "Already Executed" }timeout.enter()callStart()try {client.dispatcher.executed(this)return getResponseWithInterceptorChain()} finally {client.dispatcher.finished(this)}}

四、Dispatcher 

Dispatcher 是一个调度器,用于对全局的网络请求进行缓存调度,其包含一下几个成员变量。

var maxRequests = 64var maxRequestsPerHost = 5/** Ready async calls in the order they'll be run. */
private val readyAsyncCalls = ArrayDeque<AsyncCall>()/** Running asynchronous calls. Includes canceled calls that haven't finished yet. */
private val runningAsyncCalls = ArrayDeque<AsyncCall>()/** Running synchronous calls. Includes canceled calls that haven't finished yet. */
private val runningSyncCalls = ArrayDeque<RealCall>()

1、maxRequests  同一时间允许并发执行网络请求的最大线程数。

2、maxRequestsPerHost  同一个 host 下的最大同时请求数。

3、readyAsyncCalls  保存当前等待执行的异步任务

4、runningAsyncCalls  保存当前正在执行的异步任务。

5、runningSyncCalls  保存等钱正在执行的同步任务。 

五、getResponseWithInterceptorChain

其主要逻辑就是通过拦截器来完成整个网络请求过程。

@Throws(IOException::class)internal fun getResponseWithInterceptorChain(): Response {// Build a full stack of interceptors.val interceptors = mutableListOf<Interceptor>()interceptors += client.interceptorsinterceptors += RetryAndFollowUpInterceptor(client)interceptors += BridgeInterceptor(client.cookieJar)interceptors += CacheInterceptor(client.cache)interceptors += ConnectInterceptorif (!forWebSocket) {interceptors += client.networkInterceptors}interceptors += CallServerInterceptor(forWebSocket)val chain = RealInterceptorChain(call = this,interceptors = interceptors,index = 0,exchange = null,request = originalRequest,connectTimeoutMillis = client.connectTimeoutMillis,readTimeoutMillis = client.readTimeoutMillis,writeTimeoutMillis = client.writeTimeoutMillis)var calledNoMoreExchanges = falsetry {val response = chain.proceed(originalRequest)if (isCanceled()) {response.closeQuietly()throw IOException("Canceled")}return response} catch (e: IOException) {calledNoMoreExchanges = truethrow noMoreExchanges(e) as Throwable} finally {if (!calledNoMoreExchanges) {noMoreExchanges(null)}}}

六、interceptor 

interceptor 多个拦截器增加串行调用逻辑

package com.gxxclass Request
class Responseinterface Chain {fun request(): Requestfun proceed(request: Request): Response
}interface Interceptor {fun intercept(chain: Chain): Response
}class RealInterceptorChain(private val request: Request,private val interceptors: List<Interceptor>,private val index: Int
) : Chain {private fun copy(index: Int): RealInterceptorChain {return RealInterceptorChain(request, interceptors, index)}override fun request(): Request {return request}override fun proceed(request: Request): Response {val next = copy(index + 1)val interceptor = interceptors[index]return interceptor.intercept(next)}
}class LogInterceptor : Interceptor {override fun intercept(chain: Chain): Response {val request = chain.request()println("LogInterceptor -- getRequest")val response = chain.proceed(request)println("LogInterceptor ---- getResponse")return response}
}class HeaderInterceptor : Interceptor {override fun intercept(chain: Chain): Response {val request = chain.request()println("HeaderInterceptor -- getRequest")val response = chain.proceed(request)println("HeaderInterceptor ---- getResponse")return response}
}class CallServerInterceptor : Interceptor {override fun intercept(chain: Chain): Response {val request = chain.request()println("CallServerInterceptor -- getRequest")val response = Response()println("CallServerInterceptor ---- getResponse")return response}
}fun main() {val interceptorList = mutableListOf<Interceptor>()interceptorList.add(LogInterceptor())interceptorList.add(HeaderInterceptor())interceptorList.add(CallServerInterceptor())val request = Request()val realInterceptorChain = RealInterceptorChain(request, interceptorList, 0)val response = realInterceptorChain.proceed(request)println("main response")
}/*
fun main() {val interceptorList = mutableListOf<Interceptor>()interceptorList.add(LogInterceptor())interceptorList.add(HeaderInterceptor())val request = Request()val realInterceptorChain = RealInterceptorChain(request, interceptorList, 0)val response = realInterceptorChain.proceed(request)println("main response")
}*/

参考:

https://github.com/leavesCZY/AndroidGuide/blob/master/%E4%B8%BB%E6%B5%81%E5%BC%80%E6%BA%90%E5%BA%93%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90%EF%BC%8811%EF%BC%89OkHttp%20%E6%BA%90%E7%A0%81%E8%AF%A6%E8%A7%A3.md

相关文章:

Kotlin 中 OkHttp 使用及解析

build.gradle dependencies {//OkHttpimplementation com.squareup.okhttp3:okhttp:4.9.0 } 简单使用例子 val okHttpClient OkHttpClient.Builder().connectTimeout(Duration.ofSeconds(10)).readTimeout(Duration.ofSeconds(10)).writeTimeout(Duration.ofSeconds(10)).re…...

【C++代码】用栈实现队列,用队列实现栈--代码随想录

队列是先进先出&#xff0c;栈是先进后出。卡哥给了关于C方向关于栈和队列的4个问题&#xff1a; C中stack 是容器么&#xff1f; 使用的stack是属于哪个版本的STL&#xff1f; 使用的STL中stack是如何实现的&#xff1f; stack 提供迭代器来遍历stack空间么&#xff1f; …...

肖sir__linux详解__001

linux详解: 1、ifconfig 查看ip地址 2、6版本&#xff1a;防火墙的命令&#xff1a; service iptables status 查看防火墙状态 service iptables statrt 开启防火墙 service iptables stop 关闭防火墙 service iptables restart 重启防火墙状态 7版本&#xff1a; systemctl s…...

【Android Framework系列】第12章 RecycleView相关原理及四级缓存策略分析

1 RecyclerView简介 RecyclerView是一款非常强大的widget&#xff0c;它可以帮助您灵活地显示列表数据。当我开始学习 RecyclerView的时候&#xff0c;我发现对于复杂的列表界面有很多资源可以参考&#xff0c;但是对于简单的列表展现就鲜有可参考的资源了。虽然RecyclerView的…...

P1886 滑动窗口 /【模板】(双端队列)+双端队列用法

例题 有一个长为 n 的序列 a&#xff0c;以及一个大小为 k 的窗口。现在这个从左边开始向右滑动&#xff0c;每次滑动一个单位&#xff0c;求出每次滑动后窗口中的最大值和最小值。 例如&#xff1a; The array is [1,3,−1,−3,5,3,6,7],and k3。 输入格式 输入一共有两行…...

网络渗透day6-面试01

&#x1f609; 和渗透测试相关的面试问题。 介绍 如果您想自学网络渗透&#xff0c;有许多在线平台和资源可以帮助您获得相关的知识和技能。以下是一些受欢迎的自学网络渗透的平台和资源&#xff1a; Hack The Box: Hack The Box&#xff08;HTB&#xff09;是一个受欢迎的平…...

Docker 及 Docker Compose 安装指南

Docker 是一个开源的容器化平台&#xff0c;可以帮助我们快速构建、打包和运行应用程序。而 Docker Compose 则是用于管理多个容器应用的工具&#xff0c;可以轻松定义和管理多个容器之间的关系。现在&#xff0c;让我们开始安装过程吧&#xff01; docker 安装 apt安装 sudo…...

Gitlab创建一个空项目

1. 创建项目 Project slug是访问地址的后缀&#xff0c;跟前边的ProjectUrl拼在一起&#xff0c;就是此项目的首页地址&#xff1b; Visibility Level选择默认私有即可&#xff0c;选择内部或者公开&#xff0c;就会暴露代码。 勾选Readme选项&#xff0c;这样项目内默认会带…...

C语言-内存分布(STM32内存分析)

C/C内存分布 一、内存组成二、静态区域文本段 &#xff08;Text / 只读区域 RO&#xff09;已初始化读写数据段&#xff08;RW data -- Initialized Data Segment&#xff09;未初始化数据段&#xff08;BSS -- Block Started by Symbol&#xff09; 三、动态区域堆&#xff08…...

Linux上配置NAT

Linux系统上实现NAT上网是一个挑战性的任务&#xff0c;需要对操作系统进行合理的配置。本文将概述在Linux上实现NAT上网&#xff0c;并给出相应的工作步骤。 NAT&#xff0c;即Network Address Translation&#xff0c;是一种网络部署技术&#xff0c;可以在peivate network&…...

springboot实现简单的消息对话

目录 一、前言 二、实战步骤 步骤 1&#xff1a; 步骤 2&#xff1a; 步骤 3&#xff1a; 步骤 4&#xff1a; 一、前言 要在Spring Boot项目中实现消息对话&#xff0c;你可以使用WebSocket技术。WebSocket是一种在客户端和服务器之间提供实时双向通信的协议。 二、实…...

「Tech初见」Linux驱动之blkdev

目录 一、Motivation二、SolutionS1 - 块设备驱动框架&#xff08;1&#xff09;注册块设备&#xff08;2&#xff09;注销块设备&#xff08;3&#xff09;申请 gendisk&#xff08;4&#xff09;删除 gendisk&#xff08;5&#xff09;将 gendisk 加入 kernel&#xff08;6&a…...

ssh配置(二、登录服务器)

一. 登录 linux 服务器的两种方式 使用 ssh用户名密码 的方式登录&#xff0c;但这种方式不安全&#xff0c;密码太简单容易被暴力破解&#xff0c;密码太复杂又不容易记。使用 ssh公私钥 的方式登录。 以上两种方式都可以在图形化软件工具中配置&#xff0c;例如 finalshell…...

pytorch异常——RuntimeError:Given groups=1, weight of size..., expected of...

文章目录 省流异常报错异常截图异常代码原因解释修正代码执行结果 省流 nn.Conv2d 需要的输入张量格式为 (batch_size, channels, height, width)&#xff0c;但您的示例输入张量 x 是 (batch_size, height, width, channels)。因此&#xff0c;需要对输入张量进行转置。 注意…...

【FPGA项目】沙盘演练——基础版报文收发

​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ ​​​​​​​ 第1个虚拟项目 前言 点灯开启了我们的FPGA之路&#xff0c;那么我们来继续沙盘演练。 用一个虚拟项目&#xff0c;来入门练习&#xff0c;以此步入数字逻辑的…...

【C++技能树】继承概念与解析

Halo&#xff0c;这里是Ppeua。平时主要更新C&#xff0c;数据结构算法&#xff0c;Linux与ROS…感兴趣就关注我bua&#xff01; 继承 0. 继承概念0.1 继承访问限定符 1. 基类和派生类对象赋值兼容转换2. 继承中的作用域3. 派生类中的默认成员函数4.友元5.继承中的静态成员6.菱…...

计算机网络 第二节

目录 一&#xff0c;计算机网络的分类 1.按照覆盖范围分 2.按照所属用途分 二&#xff0c;计算机网络逻辑组成部分 1.核心部分 &#xff08;通信子网&#xff09; 1.1电路交换 1.2 分组交换 两种方式的特点 重点 2.边缘部分 &#xff08;资源子网&#xff09; 进程通信的方…...

无涯教程-机器学习 - 矩阵图函数

相关性是有关两个变量之间变化的指示&#xff0c;在前面的章节中&#xff0c;无涯教程讨论了Pearson的相关系数以及相关的重要性&#xff0c;可以绘制相关矩阵以显示哪个变量相对于另一个变量具有较高或较低的相关性。 在以下示例中&#xff0c;Python脚本将为Pima印度糖尿病数…...

Redis 高可用与集群

Redis 高可用与集群 虽然 Redis 可以实现单机的数据持久化&#xff0c;但无论是 RDB 也好或者 AOF 也好&#xff0c;都解决 不了单点宕机问题&#xff0c;即一旦单台 redis 服务器本身出现系统故障、硬件故障等问题后&#xff0c; 就会直接造成数据的丢失&#xff0c;因此需要…...

修改文件名后Git仓上面并没有修改

场景&#xff1a; 我在本地将文件夹名称由Group → group ,执行git push 后&#xff0c;远程分支上的文件名称并没有修改。 原因&#xff1a; 是我绕过了git 直接使用了系统的重命名操作。 在 Git 中&#xff0c;对于已经存在的文件或文件夹进行大小写重命名是一个敏感的操作…...

Python|GIF 解析与构建(5):手搓截屏和帧率控制

目录 Python&#xff5c;GIF 解析与构建&#xff08;5&#xff09;&#xff1a;手搓截屏和帧率控制 一、引言 二、技术实现&#xff1a;手搓截屏模块 2.1 核心原理 2.2 代码解析&#xff1a;ScreenshotData类 2.2.1 截图函数&#xff1a;capture_screen 三、技术实现&…...

web vue 项目 Docker化部署

Web 项目 Docker 化部署详细教程 目录 Web 项目 Docker 化部署概述Dockerfile 详解 构建阶段生产阶段 构建和运行 Docker 镜像 1. Web 项目 Docker 化部署概述 Docker 化部署的主要步骤分为以下几个阶段&#xff1a; 构建阶段&#xff08;Build Stage&#xff09;&#xff1a…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

pam_env.so模块配置解析

在PAM&#xff08;Pluggable Authentication Modules&#xff09;配置中&#xff0c; /etc/pam.d/su 文件相关配置含义如下&#xff1a; 配置解析 auth required pam_env.so1. 字段分解 字段值说明模块类型auth认证类模块&#xff0c;负责验证用户身份&am…...

Golang dig框架与GraphQL的完美结合

将 Go 的 Dig 依赖注入框架与 GraphQL 结合使用&#xff0c;可以显著提升应用程序的可维护性、可测试性以及灵活性。 Dig 是一个强大的依赖注入容器&#xff0c;能够帮助开发者更好地管理复杂的依赖关系&#xff0c;而 GraphQL 则是一种用于 API 的查询语言&#xff0c;能够提…...

python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)

更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

unix/linux,sudo,其发展历程详细时间线、由来、历史背景

sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

GitHub 趋势日报 (2025年06月08日)

&#x1f4ca; 由 TrendForge 系统生成 | &#x1f310; https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...