OkHttp使用篇-01-介绍及基本使用

OkHttp
square
开源Java(Kotlin)
编写的网络库,是 Java
Android
开发人员使用最广泛的网络库之一。

OkHttp
有以下 优点

GZIP

OkHttp
流行得益于它的良好的架构设计,强大的 拦截器(intercepts)
使得操纵网络十分方便;也得益于强大的生态,大量的流行库都以 OkHttp
作为底层网络框架或提供支持,譬如 Retrofit
Glide
Fresco
Moshi
Picasso
等。

版本选择

3.12.x vs 3.13+

关键变更

3.12.x
版本支持 Android 2.3+(API level 9+)
以及 Java 7+

低版本的平台缺乏对 TLSv1.2
的支持。 TLSv1
TLSv1.1
及更低版本有已知的安全隐患,不建议使用。主流的Web浏览器都宣布将于2020年早期放弃对低版本的 TLS
的支持,只提供对 TLSv1.2
及更高版本的支持。

因此 OkHttp
官方宣布对 3.12.x
版本只提供关键bug修复,而且这种支持将截止到 2020年12月31日
为止。

3.13+
支持 Android 5.0+(API level 21+)
以及 Java 8+
TLSv1
TLSv1.1
默认不再启用。

因此建议升级到 3.13+
及更高版本(当前2019.11.20最新版本为 3.14.4
),毕竟更低版本的平台的使用量已经非常少了,而且未来也缺乏支持。

升级

Android
中将 OkHttp
3.12.x
升级到 3.13+
版本,首先确认 minSdkVersion
至少为 21
Gradle Plugin
版本至少为 3.2

增加依赖:

dependencies {  
  implementation "com.squareup.okhttp3:okhttp:3.14.4"  
  ...  
}
复制代码

设置 Java
版本为 1.8
以上:

compileJava {
  sourceCompatibility = JavaVersion.VERSION_1_8
  targetCompatibility = JavaVersion.VERSION_1_8
}

android {
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
  ...  
}
复制代码

兼容 TLSv1
TLSv1.1

如果希望能享受最新版本的优化及改进,而服务端还没有提供 TLSv1.2
及更高版本的支持,可以使用如下方法以开启兼容:

val client = OkHttpClient.Builder()
    .connectionSpecs(Arrays.asList(ConnectionSpec.COMPATIBLE_TLS))
    .build();
复制代码

3.x vs 4.x

目前市面上用的最多的是 3.x
系列,相关的文章博客等大多以这个系列为基础来介绍 OkHttp
的。

github
上面的
release
记录
可以追踪到, 3.x
系列的第一个正式版本
3.0.0

从2016年1月正式发布,到目前为止(2019.11.20)最新版本为
3.14.4

4.x
系列的第一个正式版本
4.0.0

从2019年6月正式发布,到目前为止(2019.11.20)最新版本为
4.2.2

,算是比较新了。

关键变更

4.x
系列相对于 3.x
系列,最大的变更是将实现语言从 Java
变更到了 Kotlin
Kotlin
相对于 Java
来说有很多优点,具体这里就不展开了。

OkHttp
团队在实现 4.x
版本的时候,从以下三方面去努力保持和 3.x
版本的兼容性:

  1. 二进制兼容性
    :使用 OkHttp 3.x
    编译的程序使用 OkHttp 4.x
    来运行的能力
  2. Java 源码兼容性
    :使用 OkHttp 3.x
    编写的 Java
    代码升级到 OkHttp 4.x
    而不用修改 Java
    代码的能力
  3. Kotlin 源码兼容性
    :使用 OkHttp 3.x
    编译的 Kotlin
    程序使用 OkHttp 4.x
    而不用修改 Kotlin
    代码的能力

OkHttp
对前两种兼容性,除了细微的变更,都实现了兼容;而对第三种却没有实现兼容,但是通过 Kotlin
语言强大的 deprecation
特性能很容易的实现升级。

不兼容的变更

  1. OkHttpClient
    中的 final
    方法

    OkHttpClient
    中的26个访问器方法从 3.x
    中的非 final
    变更为 final
    。如果测试框架需要mock,可以使用 Call.Factory
  2. 内部 API
    变更

    okhttp3.internal
    包下的内容用于内部实现,会频繁发生变更,并不建议直接使用。官方也会保持一定的向后兼容性,但后续仍然有变更的可能。
  3. Credentials.basic()


    3.x
    basic
    方法的参数 username
    password
    如果为 null
    ,则会转成字符串 "null"
    ,而 4.x
    中这两个参数为非空字符串。
  4. HttpUrl.queryParameterValues()


    HttpUrl.queryParameterValues()
    方法的返回类型为 List<String?>

新增的 @Deprecated
方法

4.x
版本中为了向后兼容便于迁移,很多方法仍然保留了下来,但是增加了 @Deprecated
标记,这是因为 Kotlin
语言提供了更加便利的方法。这些方法未来会被移除。

譬如 3.x
OkHttpClient
中有方法:

public Authenticator authenticator() {
    return authenticator;
}
复制代码

4.x
中有同样的方法:

@JvmName("-deprecated_authenticator")
@Deprecated(
  message = "moved to val",
  replaceWith = ReplaceWith(expression = "authenticator"),
  level = DeprecationLevel.ERROR)
fun authenticator(): Authenticator = authenticator
复制代码

方法标记为 @Deprecated
,建议直接使用 val
变量。这些方法可以使用 Intellij IDEA
Android Studio
提供的 Code Cleanup
工具自动替换为建议的方法,工具路径为菜单项: Analyze
-> Code Cleanup

扩展函数

4.x
中将很多静态函数变更为扩展函数,充分利用了 Kotlin
语言的特性。譬如 Handshake.get(SSLSession)
变更为 SSLSession.handshake()
等,可以查看源代码或者看 官方文档

SAM
转换

接口中如果只定义了一个抽象方法,这个方法就叫做 单抽象方法(Single Abstract Method, SAM)

譬如, Runnable
接口的 run
方法就是最常见的 SAM

package java.lang;
public interface Runnable {

    public abstract void run();
}
复制代码

Kotlin
中调用 Java
接口中定义的 SAM
时,可以像使用 lambda
方法一样。但是同样的使用方式却不适用于 Kotlin
中定义的 SAM

Kotlin
调用 OkHttp 3.x
:

val client = OkHttpClient.Builder()
    .dns { hostname -> InetAddress.getAllByName(hostname).toList() }
    .build()
复制代码

OkHttp
升级到 4.x
后,在 Kotlin
中调用就需要修改为:

val client = OkHttpClient.Builder()
    .dns(object : Dns {
      override fun lookup(hostname: String) =
          InetAddress.getAllByName(hostname).toList()
    })
    .build()
复制代码

OkHttp
中还有很多地方会遇到这个问题, Jetbrain
官方正在努力实现 Kotlin
接口的 SAM
转换,不过目前的版本还不支持。

Companion
的导入

Java
静态方法Kotlin
中的等效实现就是 Companion
对象方法,它们的字节码是一样的,但是导入的时候写法有区别。

譬如 OkHttp 3.x
中有:

import okhttp3.CipherSuite.forJavaName
复制代码

那么升级到 OkHttp 4.x
中,就要修改为:

import okhttp3.CipherSuite.Companion.forJavaName
复制代码

使用

GET
请求

同步请求

示例如下,这个是官方的示例代码的 Kotlin
版:

val client = OkHttpClient()

fun run(url: String): String? {
    val request: Request = Request.Builder()
        .url(url)
        .build()
    client.newCall(request).execute().use { response -> return response.body?.string() }
}
复制代码

发送同步 GET
请求很简单:

  1. 创建 OkHttpClient
    实例 client
  2. 通过 Request.Builder
    构建一个 Request
    请求实例 request
  3. 通过 client.newCall(request)
    创建一个 Call
    的实例
  4. Call
    的实例调用 execute
    方法发送同步请求
  5. 请求返回的 response
    转换为 String
    类型返回

异步请求

val client = OkHttpClient()

fun run(url: String) {
    val request: Request = Request.Builder()
        .url(url)
        .build()
    client.newCall(request).enqueue(object : Callback {
        override fun onResponse(call: Call, response: Response) {
            println("onResponse: ${response.body.toString()}")
        }

        override fun onFailure(call: Call, e: IOException) {
            println("onFailure: ${e.message}")
        }
    })
}
复制代码

步骤和同步请求类似,只是调用了 Call
enqueue
方法异步请求,结果通过回调 Callback
onResponse
方法及 onFailure
方法处理。

POST
请求

同步请求

下面也是官方示例的 Kotlin
版:

import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

val JSON: MediaType = "application/json; charset=utf-8".toMediaType()
val client = OkHttpClient()

fun post(url: String, json: String): String? {
    val body: RequestBody = json.toRequestBody(JSON)
    val request: Request = Request.Builder()
        .url(url)
        .post(body)
        .build()
    client.newCall(request).execute().use { response -> return response.body?.string() }
}
复制代码

GET
同步请求类似,只是创建 Request
时通过 Request.Builder.post()
方法设置请求类型为 POST
请求并设置了请求体。

异步请求

import okhttp3.MediaType.Companion.toMediaType
import okhttp3.RequestBody.Companion.toRequestBody

val JSON: MediaType = "application/json; charset=utf-8".toMediaType()
val client = OkHttpClient()

fun post(url: String, json: String) {
    val body: RequestBody = json.toRequestBody(JSON)
    val request: Request = Request.Builder()
        .url(url)
        .post(body)
        .build()
    client.newCall(request).enqueue(object : Callback {
        override fun onResponse(call: Call, response: Response) {
            println("onResponse: ${response.body.toString()}")
        }

        override fun onFailure(call: Call, e: IOException) {
            println("onFailure: ${e.message}")
        }
    })
}
复制代码

GET
异步请求类似,同样是创建 Request
时通过 Request.Builder.post()
方法设置请求类型为 POST
请求并设置了请求体。

原文 

https://juejin.im/post/5dd5077ef265da47b60c0248

本站部分文章源于互联网,本着传播知识、有益学习和研究的目的进行的转载,为网友免费提供。如有著作权人或出版方提出异议,本站将立即删除。如果您对文章转载有任何疑问请告之我们,以便我们及时纠正。

PS:推荐一个微信公众号: askHarries 或者qq群:474807195,里面会分享一些资深架构师录制的视频录像:有Spring,MyBatis,Netty源码分析,高并发、高性能、分布式、微服务架构的原理,JVM性能优化这些成为架构师必备的知识体系。还能领取免费的学习资源,目前受益良多

转载请注明原文出处:Harries Blog™ » OkHttp使用篇-01-介绍及基本使用

赞 (0)
分享到:更多 ()

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址