Android开发老生新谈:从OkHttp原理看网络请求,kotlin扩展函数equal

Android开发老生新谈:从OkHttp原理看网络请求,flutterui模板 interceptors = interceptors, index = 0, exchange = null, request = originalRequest, connectTimeoutMillis = client.connectTimeoutMillis, readTimeoutMillis = client.readTimeoutMillis, writeTimeoutMillis = client.writeTimeoutMillis ) … try { val response = ch 阅读详情

interceptors += BridgeInterceptor(client.cookieJar)

interceptors += CacheInterceptor(client.cache)

interceptors += ConnectInterceptor

if (!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

)

…

try {

val response = chain.proceed(originalRequest)

…

return response

}

…

}

getResponseWithInterceptorChain()的内部实现是通过一个责任链模式来完成,将网络请求的各个阶段封装到各个链条中(即各个拦截器Interceptor),配置好各个Interceptor后将其放在⼀个List⾥,然后作为参数,创建⼀个RealInterceptorChain对象,并调⽤ chain.proceed(request)来发起请求和获取响应。

在每一条拦截器中,会先做一些准备动作,例如对该请求进行是否可用的判断,或者将请求转换为服务器解析的格式,等等,接着就对请求执行chain.proceed(request)。上面提到getResponseWithInterceptorChain()的内部实现是一个责任链模式,而chain.proceed(request)的作用就是责任链模式的核心所在,将请求移交给下一个拦截器。

OkHttp中连自定义拦截器包括在内,一共有7种拦截器,在这里,网络请求的细节就封装在各个拦截器中,每个拦截器也都有自己的职责,只要把每个拦截器研究清楚,整个网络请求也就明了了。下面就来一一分析这些拦截器的职责。

7种拦截器的职责


1、用户自定义拦截器interceptors

用户自定义拦截器是在所有其他拦截器之前,开发者可根据业务需求进行网络拦截器的自定义,例如我们常常自定义Token处理拦截器,日志打印拦截器等。

2、RetryAndFollowUpInterceptor

RetryAndFollowUpInterceptor是一个请求失败和重定向时重试的拦截器。它的内部开启了一个请求循环,每次循环都会先做一个准备动作(call.enterNetworkInterceptorExchange(request, newExchangeFinder)),这个准备动作最主要的目的在于创建一个ExchangeFinder,为请求寻找可用的Tcl或者Tsl连接以及设置跟连接相关的一些参数,如连接编码解码器等。 ExchangeFinder在后面网络连接时,会详细说明。

准备工作做好后便开始了一个网络请求(response = realChain.proceed(request)),这句代码的目的是为了将请求传递给下一个拦截器。同时,会判断当前请求是否会出错以及是否需要重定向。如果出错或者需要重定向,那么就又开始新一轮的循环,直到没有出错和需要重定向为止。

这里出错和重定向的判断标准也简单说一下:

  • 判断出错的标准: 利用try-catch块对请求进行异常捕获,这里会捕获RouteException和IOException,并且在出错后都会先判断当前请求是否能够进行重试的操作。

  • 重定向标准: 这里判断是否需要重定向,是对Response的状态码Code进行审查,当状态码为3xx时,则表示需要重定向,而后创建一个新的request,进行重试操作。

3、BridgeInterceptor

BridgeInterceptor是用来连接应用程序代码和网络代码的一个拦截器。也就是说该拦截器会帮用户准备好服务器请求所需要的一些配置。可能定义太抽象,我们就先来看一下一个请求Url所对应的服务器请求头是怎么样的?

URL: wanandroid.com/wxarticle/c…

方法: GET

那它所对应的请求头如下:

GET /wxarticle/chapters/json HTTP/1.1

Host: wanandroid.com

Accept: application/json, text/plain, /

Accept-Encoding: gzip, deflate, br

Accept-Language: zh-CN,zh;q=0.9

Connection: keep-alive

User-Agent: Mozilla/5.0 xxx

…

你可能会问,BridgeInterceptor拦截器和这个有什么关系?其实BridgeInterceptor的作用就是帮用户处理网络请求,它会帮助用户填写服务器请求所需要的配置信息,如上面所展示的User-Agent、Connection、Host、Accept-Encoding等。同时也会对请求的结果进行相应处理。

BridgeInterceptor的内部实现主要分为以下三步:

  1. 为用户网络请求设置Content-Type、Content-Length、Host、Connection、Cookie等参数,也就是将一般请求转换为适合服务器解析的格式,以适应服务器端;

  2. 通过 chain.proceed(requestBuilder.build())方法,将转换后的请求移交给下一个拦截器CacheInterceptor,并接收返回的结果Response;

  3. 对结果Response也进行gzip、Content-Type转换,以适应应用程序端。

所以说BridgeInterceptor是应用程序和服务器端的一个桥梁。

4、CacheInterceptor

CacheInterceptor是一个处理网络请求缓存的拦截器。它的内部处理和一些图片缓存的逻辑相似,首先会判断是否存在可用的缓存,如果存在,则直接返回缓存,反之,调用chain.proceed(networkRequest)方法将请求移交给下一个拦截器,有了结果后,将结果put到cache中。

5、ConnectInterceptor

ConnectInterceptor是建立连接去请求的拦截器。

internal fun initExchange(chain: RealInterceptorChain): Exchange {

…

val exchangeFinder = this.exchangeFinder!!

val codec = exchangeFinder.find(client, chain)

val result = Exchange(this, eventListener, exchangeFinder, codec)

this.interceptorScopedExchange = result

this.exchange = result

…

if (canceled) throw IOException(“Canceled”)

return result

}

从它的源码可以看到,它首先会通过ExchangeFinder查询到codec,这个ExchangeFinder是不是很熟悉?在上面RetryAndFollowUpInterceptor分析中,每次循环都会先做创建ExchangeFinder的准备工作。

而这个codec是什么?它是一个编码解码器,来确定是用Http1的方式还是以Http2的方式进行请求。

在找到合适的codec后,作为参数创建Exchange。Exchange内部涉及了很多网络连接的实现,这个后面再详细说,我们先看看是如何找到合适的codec?

如何找到可用连接?

找到合适的codec,就必须先找到一个可用的网络连接,再利用这个可用的连接创建一个新的codec。 为了找到可用的连接,内部使用了大概5种方式进行筛选。

第一种:从连接池中查找

if (connectionPool.callAcquirePooledConnection(address, call, null, false)) {

val result = call.connection!!

return result

}

尝试在连接池中查找可用的连接,在遍历连接池中的连接时,就会判断每个连接是否可用,而判断连接是否可用的条件如下:

  1. 请求数要小于该连接最大能承受的请求数,Http2以下,最大请求数为1个,并且此连接上可创建新的交换;

  2. 该连接的主机和请求的主机一致;

如果从连接池中拿到了合格的连接connection,则直接返回。

如果没有拿到,那就进行第二种拿可用连接的方式。

第二种:传入Route,从连接池中查找

if (connectionPool.callAcquirePooledConnection(address, call, routes, false)) {

val result = call.connection!!

return result

}

第二种依然是从连接池中拿,但是这次不同的是,参数里传入了routes,这个routes是包含路由Route的一个List集合,而Route其实指的是连接的IP地址、TCP端口以及代理模式。

而这次从连接池中拿,主要是针对Http2,路由必须共用一个IP地址,此连接的服务器证书必须包含新主机且证书必须与主机匹配。

第三种:自己创建连接

如果前两次从连接池里都没有拿到可用连接,那么就自己创建连接。

val newConnection = RealConnection(connectionPool, route)

call.connectionToCancel = newConnection

try {

newConnection.connect(

connectTimeout,

readTimeout,

writeTimeout,

pingIntervalMillis,

connectionRetryEnabled,

call,

eventListener

)

}

创建连接其实是内部自己在进行socket,tls的连接,这里抛出一个问题在后面解答:TCP/TLS连接是如何实现的?

自己创建好连接后,又做了一次从连接池中查找的操作。

第四种:多路复用置为true,依然从连接池中查找

if (connectionPool.callAcquirePooledConnection(address, call, routes, true)) {

val result = call.connection!!

newConnection.socket().closeQuietly()

return result

}

这次从连接池中查找,requireMultiplexed置为了true,只查找支持多路复用的连接。并且在建立连接后,将新的连接保存到连接池中。

如何找到Http1和Http2的编/解码器?

上面已经分析出寻找可用且健康的连接的几种方式,那对于codec的创建则需要根据这些连接进行Http1和Http2的区分。如果http2Connection不为null,则创建Http2ExchangeCodec,反之创建Http1ExchangeCodec。

找到编解码器后,我们就回到ConnectInterceptor的一开始,利用编解码器codec创建了一个Exchange,而这个Exchange的内部其实是利用Http1解码器或者Http2解码器,分别进行请求头的编写writeRequestHeaders,或者创建Request Body,发送给服务器。

Exchange初始化成功后,就又将请求移交给了下一个拦截器CallServerInterceptor。

6、CallServerInterceptor

CallServerInterceptor是链中最后一个拦截器,主要用于向服务器发送内容,主要传输http的头部和body信息。

其内部利用上面创建的Exchange进行请求头编写,创建Request body,发送请求,得到结果后,对结果进行解析并回传。

7、NetworkInterceptor

networkInterceptor也是属于用户自定义的一种拦截器,它的位置在ConnectInterceptor之后,CallServerInterceptor之前。我们知道第一个拦截器便是用户自定义,那和这个有什么区别呢?

networkInterceptor前面已经存在有多个拦截器的使用,在请求到达该拦截器时,请求信息已经相当复杂了,其中就包括RetryAndFollowUpInterceptor重试拦截器,经过分析知道,每当重试一次,其后面的拦截器也都会被调用一次,这样就导致networkInterceptor也会被调用多次,而第一个自定义拦截器只会调用一次。当我们需要自定义拦截器时,如token、log,为了资源消耗这一点,一般都是使用第一个。

到这里为止,7种拦截器都分析完成。在分析ConnectInterceptor时抛出了一个问题:TCP/TLS连接是如何实现的?

如何建立TCP/TLS连接?

================================================================================

TCP连接


fun connect(

connectTimeout: Int,

readTimeout: Int,

writeTimeout: Int,

pingIntervalMillis: Int,

connectionRetryEnabled: Boolean,

call: Call,

eventListener: EventListener

) {

…

while (true) {

try {

if (route.requiresTunnel()) {

connectTunnel(connectTimeout, readTimeout, writeTimeout, call, eventListener)

if (rawSocket == null) {

// We were unable to connect the tunnel but properly closed down our resources.

break

}

} else {

connectSocket(connectTimeout, readTimeout, call, eventListener)

}

establishProtocol(connectionSpecSelector, pingIntervalMillis, call, eventListener)

eventListener.connectEnd(call, route.socketAddress, route.proxy, protocol)

break

} catch (e: IOException) {

…

}

  1. 在connect的内部开启了一个while循环,可以看到第一步就是route.requiresTunnel()判断,这个requiresTunnel()方法表示该请求是否使用了Proxy.Type.HTTP代理且目标是Https连接;

  2. 如果是,则创建一个代理隧道连接Tunnel(connectTunnel)。创建这个隧道的目的在于利用Http来代理请求Https;

  3. 如果不是,则直接建立一个TCP连接(connectSocket);

  4. 建立请求协议。

代理隧道是如何创建的?它的内部会先通过Http代理创建一个TLS的请求,也就是在地址url上增加Host、Proxy-Connection、User-Agent首部。接着最多21次的尝试,利用connectSocket开启TCP连接且利用TLS请求创建一个代理隧道。

从这里可以看见,不管是否需要代理隧道,都会开始建立一个TCP连接(connectSocket),那又是如何建立TCP连接的?

private fun connectSocket(

connectTimeout: Int,

readTimeout: Int,

call: Call,

eventListener: EventListener

) {

val proxy = route.proxy

val address = route.address

val rawSocket = when (proxy.type()) {

Proxy.Type.DIRECT, Proxy.Type.HTTP -> address.socketFactory.createSocket()!!

else -> Socket(proxy)

}

this.rawSocket = rawSocket

eventListener.connectStart(call, route.socketAddress, proxy)

rawSocket.soTimeout = readTimeout

try {

Platform.get().connectSocket(rawSocket, route.socketAddress, connectTimeout)

} catch (e: ConnectException) {

throw ConnectException(“Failed to connect to ${route.socketAddress}”).apply {

initCause(e)

}

}

…

}

从源码上看,如果代理类型为直连或者HTTP/FTP代理,则直接创建一个socket,反之,则指定代理类型进行创建。我们看到创建后返回了一个rawSocket,这个就代表着TCP连接。在最后 调用Platform.get().connectSocket,而这实际就是调用socket的connect方法来打开一个TCP连接。

TLS连接


在建立TCP连接或者创建Http代理隧道后,就会开始建立连接协议(establishProtocol)。

private fun establishProtocol(

connectionSpecSelector: ConnectionSpecSelector,

pingIntervalMillis: Int,

call: Call,

eventListener: EventListener

) {

if (route.address.sslSocketFactory == null) {

if (Protocol.H2_PRIOR_KNOWLEDGE in route.address.protocols) {

socket = rawSocket

protocol = Protocol.H2_PRIOR_KNOWLEDGE

startHttp2(pingIntervalMillis)

return

}

socket = rawSocket

protocol = Protocol.HTTP_1_1

return

}

eventListener.secureConnectStart(call)

connectTls(connectionSpecSelector)

eventListener.secureConnectEnd(call, handshake)

if (protocol === Protocol.HTTP_2) {

startHttp2(pingIntervalMillis)

}

}

  1. 判断当前地址是否是HTTPS;

  2. 如果不是HTTPS,则判断当前协议是否是明文HTTP2,如果是的则调用startHttp2,开始Http2的握手动作,如果是Http/1.1则直接return返回;

  3. 如果是HTTPS,就开始建立TLS安全协议连接了(connectTls);

  4. 如果是HTTPS且为HTTP2,除了建立TLS连接外,还会调用startHttp2,开始Http2的握手动作。

在上述第3步时就提到了TL

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

S的连接(connectTls),那我们就来看一下它的内部实现:

“深入交流“系列:Okhttp(一)请求流程解析 Okhttp请求流程源码解析 前言 最近发现以前学习过的好多东西,都忘记了,所以打算复习一次,并且通过输出博客来加深印象。Okhttp准备分成两篇文章来讲解,这篇文章主要叙述一下Okhttp的整体请求流程,第二篇文章则讲述一下Okhttp中极为重要的拦截器。“深入交流”系列打算从一些第三方框架源码或者FrameWork层源码入手,进行"深入"的交流,会持续输出下去,敬请期待。 1、Okhttp的同步请求和异步请求 在分析Okhttp的源码之前,我们首先了解一下Okhttp最基本的实现一次网络请求的方式。 O 阅读详情

相关推荐

OkHttp3源码详解(一) Request类,2021年Android开发实战

HttpUrl主要用来规范普通的url连接,并且解析url的组成部分 现通过下面的例子来示例httpUrl的使用 https://www.google.com/search?q=maplejaw ①使用parse解析url字符串: HttpUrl url = HttpUrl.parse(“https://www.google.com/search?q=maplejaw”); ②通过构造者模式来常见: HttpUrl url = new HttpUrl.Builder() .scheme(“

m0_65145426的博客 1957

okhttp之Request

转载请以链接形式标明出处: 本文出自:103style的博客 base on 3.12.0 目录 Request 简介 Request相关的配置方法 Header介绍 Request 简介 Request即我们构建的每一个HTTP请求。通过配置请求的 地址、http方法、请求头 等信息。 使用方法: Request request = new Request.Builder() ...

103style 2261

OkHttp3源码详解(一) Request类,从青铜到王者的路线

现通过下面的例子来示例httpUrl的使用q=maplejaw②通过构造者模式来常见:.build();``````````Headers用于配置请求头,对于请求头配置大家一定不陌生吧,比如User-Agent和`Cache-Control等等。还可以使用它的重载方法of(Map map)方法来创建(2)构建者模式创建:``````````````````````````.set(“name1”,“value1”)//set表示name1是唯一的,会覆盖掉已经存在的。

2301_82257317的博客 1081

深入解读OkHttp3中的Request5

在 OkHttp 中,`Request` 类用于表示一个 HTTP 请求。它包含了请求的 URL、HTTP 方法、请求头和请求体等信息。

jiet_h的博客 1610

Trae CN 使用入门指南

【代码】Trae CN 使用入门指南。

weixin_42551921的博客 8770

ENVI遥感技术

记录2024.03.06所遇到的遥感问题

qq_44453923的博客 4332

kotlin匿名内部类写法,你还看不懂吗

板 ,列出来,有计划的去完成,别看前两天掘金一些大佬在驳来驳去 ,他们的观点是他们的,不要因为他们的观点,膨胀了自己,影响自己的学习节奏。基础很大程度决定你自己技术层次的厚度,你再熟练框架也好,也会比你便宜的,性价比高的替代,很现实的问题但也要有危机意识,当我们年级大了,有哪些亮点,与比我们经历更旺盛的年轻小工程师,竞争。当我们出去找工作,或者准备找工作的时候,我们一定要想,我面试的目标是什么,我自己的技术栈有哪些,近期能掌握的有哪些,我的哪些短。6、说下四大组件的启动过程,四大组件的启动与销 毁的方式。

m0_61331573的博客 949

ESP32实战:破解校园网WPA2-Enterprise认证的完整指南

本文详细介绍了如何使用ESP32开发板破解校园网WPA2-Enterprise认证的完整指南。通过硬件准备、环境搭建、核心代码实现及常见问题排查,帮助开发者解决企业级WiFi连接难题,特别适用于校园网环境下的物联网设备开发。

weixin_29194817的博客 457

是面试官放水,还是公司太缺人?这都没挂,2024的字节跳动也太好进了吧!(面经+经验分享)

一线互联网Android面试题含详解(初级到高级专题)这些题目是今年群友去腾讯、百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目。并且大多数都整理了答案,熟悉这些知识点会大大增加通过前两轮技术面试的几率如果设置门槛,很多开发者朋友会因此错过这套高级架构资料,错过提升成为架构师的可能。这就失去了我们的初衷;让更多人都能通过高效高质量的学习,提升自己的技术和格局,升职加薪。最后送给大家一句话,望共勉,永远不要放弃自己的梦想和追求;

hnsgsdsagaaq的博客 785

工业模型导入Unity实战:从ProE/SolidWorks到实时渲染的完整流程

在工业仿真、数字孪生和VR/AR应用开发中,将高精度工程模型导入实时渲染引擎是一个常见的技术挑战。其核心原理在于参数化工程软件与实时渲染引擎的数据结构差异:前者基于精确的B-rep边界表示和特征树,后者依赖轻量化的三角网格与材质贴图。这一转换的技术价值在于实现工程数据的可视化与交互化,为产品展示、虚拟培训和工厂仿真等应用场景提供基础。通过数据翻译与优化流程,特别是利用3ds Max或Blender作为中转站进行网格优化与UV展开,能够有效解决模型破面、材质丢失和性能问题。本文聚焦于ProE(Creo)和So

weixin_33050117的博客 344

硅基半导体量子点:单电子自旋量子比特技术手册

现在我们已经了解了从硅片到容错计算的全部环节,让我们用一张总览图把碎片拼成完整拼图。fill:#333;important;important;fill:none;color:#333;color:#333;important;fill:none;fill:#333;height:1em;important;important;important;color:#000!important;important;important;important;important;color:#000!

VectorShift的博客 375

是面试官放水,还是公司太缺人?这都没挂,2024的字节跳动也太好进了吧!(面经+经验分享)(1)

各行各样都会淘汰一些能力差的,不仅仅是IT这个行业,所以,不要被程序猿是吃青春饭等等这类话题所吓倒,也不要觉得,找到一份工作,就享受安逸的生活,你在安逸的同时,别人正在奋力的向前跑,这样与别人的差距也就会越来越遥远,加油,希望,我们每一个人,成为更好的自己。BAT大厂面试题、独家面试工具包,资料包括 数据结构、Kotlin、计算机网络、Framework源码、数据结构与算法、小程序、NDK、Flutter,《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》点击传送门,即可获取!

2401_84010457的博客 364

V-Mamba:2D 选择性扫描状态空间模型图像分类

V-Mamba CIFAR-10 分类链路:32² RGB → Stem Conv (3→64ch, stride2→16²) → VMambaBlock ×4 (SS2D 四方向 → Mamba S6 扫描 → MLP) → GAP → Linear → 10 类。核心贡献:SS2D 四方向扫描将 2D 空间建模转为 4 个 1D 序列, 计算复杂度从 O(N²) 降至 O(N)。建议先从 CIFAR-10 dim=64 depth=4 验证 SSM 收敛性;

FJN110的博客 70

大咖的一周面试想法(附咕咚美团面试题)

不少小伙伴还是在公众号私信问我上周怎么突然没有日更了,我也有在公众号中答应大家后面会给回复。好啦,现在还是简单说一下吧。 过去的一周中,我主要是出去找工作去啦~过去的一周,面了 4 家公司,从小到大都有,最终斩获了 3 个 offer。在经历了一番内心挣扎之后,我于周二上午决心选择了福利待遇相对较差一些的咕咚。 主要还是因为咕咚的面试官给我的印象非常深刻,我很高兴能够加入一家技术氛围如此淳厚的...

weixin_43901866的博客 659

56、宇宙微波背景辐射(CMB)望远镜及光学系统解析

本文详细解析了宇宙微波背景辐射(CMB)望远镜及其光学系统,重点介绍了交叉德拉贡系统的结构特点、偏振测量误差及其控制、以及大型地面望远镜如ACT和SPT的设计与对比。同时,总结了不同光学系统和探测器阵列的优劣势,并展望了未来发展方向,旨在为CMB研究提供更高效的工具和技术支持。

f9g0h的博客 243

RT-DETR改进策略【模型轻量化】| 替换骨干网络为 2024轻量化网络MoblieNetV4:移动生态系统的通用模型

本文记录的是基于MobileNet V4的RT-DETR目标检测轻量化改进方法研究。通过整合UIBMobile MQA以及优化的NAS策略能够在在不降低性能指标的前提下,降低计算成本。本文配置了原论文中和五种模型,以满足不同的需求。

Limiiiing的博客 1923

OkHttp-Request-请求执行流程

OkHttp不同版本的代码差异挺大的,本篇文章中分析的源码是基于OkHttp 3.6.0版本进行的。 《OkHttp Request 请求执行流程》 《OkHttp - Interceptors(一)》 《OkHttp - Interceptors(二)》 《OkHttp - Interceptors(三)》 《OkHttp - Interceptors(四)》 一、 Request任务的调...

weixin_34241036的博客 546

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

Java(7):OkHttp基本使用

OkHttp简介 OkHttp是目前非常火的网络库,它有以下特性: 1.支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接 2.连接池减少请求延时 3.透明的GZIP压缩减少响应数据的大小 4.缓存响应内容,避免一些完全重复的请求 OkHttp基本使用 可参考官网:https://square.github.io/okhttp/ OkHttpClient:客户端对象 Request:访问请求,Post请求中需要包含RequestBody RequestBody:请求

fen_fen的专栏 1万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

okhttp的Request怎么获取url

okhttp 的 Request 类有一个方法叫做 url() ,可以用来获取 URL。你可以这样使用: Request request = new Request.Builder().url("https://www.example.com").build(); String url = request.url().toString(); 或者,你也可以这样获取 URL: HttpUrl ur...

weixin_42576467的博客 717

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

网络请求(二)— OkHttp

OkHttp简介 由Square公司开发并共享开源的高效网络访问框架,使用简单,它替代了HttpUrlConnection和Apache的HttpClient。 默认情况下OkHttp具备以下特性: 支持HTTP/2,允许所有同一个主机地址的请求共享同一个Socket连接 连接池减少请求延时 透明的GZIP压缩较少响应数据的大小 缓存响应内容,避免一些完全重复的请求 网络出现问题后,OkHttp保持不变,自动从问题中恢复 OKHttp双任务队列机制 OKHttp实现异步请求采用了双任务队队列机制,通过

xingyu19911016的博客 1万+

OKHttp入门详解

4、OKHttp详解 https://www.jianshu.com/p/9aa969dd1b4d 在AndroidManifest.xml中加入联网权限 <uses-permission android:name="android.permission.INTERNET" /> 1、拿到OkHttpClient对象 OkHttpClient okHttpClient = new OkHttpClient() 2、构造Request对象 Request request = new Requ

weixin_45552475的博客 511

OKHttp3网络请求,接口处理

基于OKHttp3,整理常用的请求处理方法; 1、获取Get请求的参数 private fun paramsToJson4Get(url: String): Map<String, String> { val map = mutableMapOf<String, String>() try { val uri: Uri = Uri.parse(url) for (paramName in ur.

唐诺 1245

okhttp3相关封装配置(二):Request对象

okhttp3框架使用中,对于Get请求和Post请求,Request对象的生成。如何传入参数,配置请求头。

hedgehog_ming的博客 1908

OkHttp系列一、使用OkHttp进行网络请求的4个步骤

我们创建OkHttpClient客户端的方式通常有两种: 方式一、OkHttpClient client = new OkHttpClient(); 方式二、OkHttpClient okHttpClient = new OkHttpClient.Builder().build(); 上面二者等价,都是创建一个OkHttpClient客户端,其实打开new OkHttpClient()源码我们可...

haoyuegongzi的博客 2810

OkHttp使用教程

Android系统提供了两种HTTP通信类,HttpURLConnection和HttpClient。 关于HttpURLConnection和HttpClient的选择>>官方博客 尽管Google在大部分安卓版本中推荐使用HttpURLConnection,但是这个类相比HttpClient实在是太难用,太弱爆了。 OkHttp是一个相对成熟的解决方案,据说Android4.4的源码中可

夏皓 7万+

OkHttp的使用

概述 OkHttp是一款优秀的HTTP框架,它支持get请求和post请求,支持基于Http的文件上传和下载,支持加载图片,支持下载文件透明的GZIP压缩,支持响应缓存避免重复的网络请求,支持使用连接池来降低响应延迟问题。 OkHttp官网地址:http://square.github.io/okhttp/ OkHttp GitHub地址:https://github.com/square...

wen_haha的博客 1193
上一篇: Android开发简记:Java和Android程序员都应该掌握的虚拟机知识
下一篇: Android开发要达到阿里P7水平,很难吗,rxjava面试题
flutter架构师
博客等级 码龄5年 47粉丝 133原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值