当前位置: 首页 > 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;对于已经存在的文件或文件夹进行大小写重命名是一个敏感的操作…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

在rocky linux 9.5上在线安装 docker

前面是指南&#xff0c;后面是日志 sudo dnf config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo sudo dnf install docker-ce docker-ce-cli containerd.io -y docker version sudo systemctl start docker sudo systemctl status docker …...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

什么是EULA和DPA

文章目录 EULA&#xff08;End User License Agreement&#xff09;DPA&#xff08;Data Protection Agreement&#xff09;一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA&#xff08;End User License Agreement&#xff09; 定义&#xff1a; EULA即…...

DBAPI如何优雅的获取单条数据

API如何优雅的获取单条数据 案例一 对于查询类API&#xff0c;查询的是单条数据&#xff0c;比如根据主键ID查询用户信息&#xff0c;sql如下&#xff1a; select id, name, age from user where id #{id}API默认返回的数据格式是多条的&#xff0c;如下&#xff1a; {&qu…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

Device Mapper 机制

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