OkHttp:使用篇

本文介绍了OkHttp的基本使用,包括创建配置对象、发起GET和POST请求、文件下载和上传、取消请求以及拦截器的使用。OkHttp支持HTTP/2协议,提供高效连接池,支持同步和异步请求,并允许自定义请求和响应的处理。
摘要由CSDN通过智能技术生成

1、 简介

OkHttp 是一个默认高效的 HTTP 客户端:

  • 支持 HTTP/2 允许对同一主机的所有请求共享一个套接字。
  • 连接池减少了请求延迟(如果 HTTP/2 不可用)。
  • 透明 GZIP 缩小了下载大小。
  • 响应缓存完全避免了网络重复请求。

2、引入依赖

implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.2'

当然网络请求需要网络请求权限,这个不要忘记在 AndroidManifest 中进行配置

<uses-permission android:name="android.permission.INTERNET"/>

3、创建 OkHttpClient 对象

在使用 OkHttp 发送 HTTP 请求时,首先需要获取一个 OkHttpClient 对象,获取 OkHttpClient 对象的方式很简单,在 OkHttp 中大量使用了 Builder 模式。

①、获取默认配置对象

val myHttpClient: OkHttpClient = OkHttpClient.Builder().build()

②、获取自定配置对象

在获取对象时可以指定,连接超时、读写超时、拦截器等配置

val myHttpClient: OkHttpClient = OkHttpClient.Builder()
    //设置连接超时时间
    .connectTimeout(Duration.ofSeconds(30))
    //设置读超时时间
    .readTimeout(Duration.ofSeconds(60))
    //设置写超时时间
    .writeTimeout(Duration.ofSeconds(60))
    //设置完整请求超时时间
    .callTimeout(Duration.ofSeconds(120))
    //添加一个拦截器
    .addInterceptor { chain ->
        val request = chain.request()
        chain.proceed(request)
    }.eventListener(object : EventListener() {
        override fun callEnd(call: Call) {
            super.callEnd(call)
        }
    })
    .build()

4、GET 请求

①、get请求同步(无参数)

fun httpGetSyncTest() {
    val myUrl="https://www.wanandroid.com/banner/json"
    // 创建一个 Request
    val request: Request = Request.Builder()
        .get()//声明用get请求
        .url(myUrl)
        .build()
    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = myHttpClient.newCall(request)

    // 执行同步请求 execute
    val response = newCall.execute()
    // 判断是否请求成功
    if (response.isSuccessful) {
        println("request success")
        println("response ${response.body?.string()}")
    } else {
        println("request fail")
    }
}
 
 //执行结果
request success
response {"data":[{......}],"errorCode":0,"errorMsg":""}

注意:

  1. 同步请求不能在Android的主线程中进行,否则会出现崩溃问题
  2. response.body?.string() 与 response.body?.toString() 的区别

使用toString()只能获取到如下结果:

response okhttp3.internal.http.RealResponseBody@609bc9f

②、get请求异步(无参数)

fun httpGetAsyncTest() {
    val myUrl="https://www.wanandroid.com/banner/json"
    //创建一个 Request
    val request: Request = Request.Builder()
        .get()//声明用get请求
        .url(myUrl)
        .build()
    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = myHttpClient.newCall(request)

    // 执行异步请求 enqueue
    newCall.enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            println("onFailure $e")
        }

        override fun onResponse(call: Call, response: Response) {
            val body = response.body?.string()
            println("request success $body")
        }
    })
}
    
//执行结果
request success {"data":[{......}],"errorCode":0,"errorMsg":""}

③、get请求异步(有参数)

fun httpGetAsyncParam() {
    val urlStr = "https://v.api.aa1.cn/api/api-tianqi-3/index.php"
    //为url添加参数
    val newUrl = urlStr.toHttpUrlOrNull()?.newBuilder()
        ?.apply {
            addQueryParameter("msg", "天津")
            addQueryParameter("type", "1")
        }!!.build()

    //创建一个 Request
    val request: Request = Request.Builder()
        .get()
        .url(newUrl)
        .build()

    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = myHttpClient.newCall(request)

    // 执行异步请求 enqueue
    newCall.enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            println("onFailure $e")
        }

        override fun onResponse(call: Call, response: Response) {
            val body = response.body?.string()
            println("request success $body")
        }
    })

}

5、POST 请求

POST 请求的构建步骤与GET 相似,区别是,在构建 Request 对象时 在post() 方法中,设置需要发送的数据,发送的数据可为目前流行的 JSON 格式数据,也可以模拟 Form表单提交的数据

①、构造 JSON 数据,同步请求

fun httpPostJsonSyncTest() {

    val JSON: MediaType = "application/json".toMediaType()
    val myUrl = "https://www.wanandroid.com/blog/show/2"

    //Json 参数
    val json = JSONObject()
    json.put("username", "Derry-vip")
    json.put("password", "123456")

    //获取 requestBody
    val requestBody: RequestBody = json.toString().toRequestBody(JSON)

    val request: Request = Request.Builder()
        .post(requestBody)
        .url(myUrl)
        .build()

    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = myHttpClient.newCall(request)
    // 执行同步请求execute
    val response = newCall.execute()
    //判断是否请求成功
    if (response.isSuccessful) {
        println("request success")
        println("response ${response.body?.string()}")
    } else {
        println("request fail")
    }
}

②、构造 JSON 数据,异步请求

fun httpPostJsonAsyncTest() {
    val JSON: MediaType = "application/json".toMediaType()
    val myUrl = "https://www.wanandroid.com/blog/show/2"

    //Json 参数
    val json = JSONObject()
    json.put("username", "Derry-vip")
    json.put("password", "123456")

    //获取 requestBody
    val requestBody: RequestBody = json.toString().toRequestBody(JSON)

    val request: Request = Request.Builder()
        .post(requestBody)
        .url(myUrl)
        .build()

    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = OkHttpUtils.myHttpClient.newCall(request)

    //post 异步请求
    newCall.enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            println("onFailure $e")
        }

        override fun onResponse(call: Call, response: Response) {
            val body = response.body?.string()
            println("request success $body")
        }
    })
}

③、构建Form表单

fun httpPostFormSyncTest() {
    val myUrl = "https://www.wanandroid.com/blog/show/2"

    //创建表单
    val formBody: FormBody = FormBody.Builder()
        .addEncoded("username", "Derry-vip")
        .add("password", "123456")
        .build()

    val request: Request = Request.Builder()
        .post(formBody)
        .url(myUrl)
        .build()

    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = OkHttpUtils.myHttpClient.newCall(request)
    // 执行同步请求execute
    val response = newCall.execute()
    //判断是否请求成功
    if (response.isSuccessful) {
        println("request success")
        println("response ${response.body?.string()}")
    } else {
        println("request fail")
    }
}

6、文件下载

fun downFileTest() {
    val downUrl="https://img-blog.csdnimg.cn/20200614120050920.JPG"
    //创建请求
    val request = Request.Builder()
        .url(downUrl)
        .build()
    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = OkHttpUtils.myHttpClient.newCall(request)

    //异步执行请求
    newCall.enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            //请求失败,提示下载失败信息
            println("onFailure $e")
        }

        override fun onResponse(call: Call, response: Response) {
            //请求成功,获取到资源
            println("success $response")
            //下载文件,将response 转成 inputStream ,然后写入文件中
            writeToSDCard(response)
        }
    })
}

注意:

  1. 文件下载记得要 AndroidManifest 中进行配置权限
  2. 配置权限后还要在界面中进行动态申请权限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

7、文件上传

fun upFileTest() {
    val myUrl = "https://mytodoserver.com/new"
    val file = File("path/of/attachment.png")
	
	// 使用 MultipartBody 构造 RequestBody对象
    val requestBody = MultipartBody.Builder()
        .addFormDataPart("image", "attachment.png", file.asRequestBody("image/png".toMediaType()))
        //一定要设置这句
        .setType(MultipartBody.FORM)
        .build()

    val postRequest = Request.Builder()
        .url(myUrl)
        .post(requestBody)
        .build();

    val response = OkHttpUtils.myHttpClient.newCall(postRequest).execute()

    //判断是否请求成功
    if (response.isSuccessful) {
        println("request success")
        println("response ${response.body?.string()}")
    } else {
        println("request fail")
    }
}

8、MediaType介绍

类型描述
text/htmlHTML格式
text/plain纯文本格式,空格转换为 “+” 加号,不对特殊字符编码
text/xmlXML格式
text/x-markdownMarkdown格式
image/gifgif图片格式
image/jpegjpg图片格式
image/pngpng图片格式
application/xhtml+xmlXHTML格式
application/xmlXML数据格式
application/json用来告诉服务端,消息主体是序列化后的JSON字符串
application/pdfpdf格式
application/mswordWord文档格式
application/octet-stream二进制流数据
application/x-www-form-urlencoded参数为键值对形式,在发送前编码所有字符(默认)。如果不设置 enctype 属性,那么最终就会以 application/x-www-form-urlencoded 方式提交数据
multipart/form-data不对字符编码,发送大量二进制数据或包含non-ASCII字符的文本,application/x-www-form-urlencoded是效率低下的(需要用更多字符表示一个non-ASCII字符)。需要设定“ <form enctype=‘multipart/form-data’

MediaType对象解析

text/html; charset=utf-8
//解析
type值是text,表示是文本这一大类;
后面的html是子类型,表示是文本这一大类下的html类型;
charset=utf-8 则表示采用UTF-8编码

9、取消请求

在需要的场景上可以通过 Call 对象取消请求 cancel

fun httpGetAsyncCancelTest() {
    val myUrl = "https://www.wanandroid.com/banner/json"
    //创建一个 Request
    val request: Request = Request.Builder()
        .get()//声明用get请求
        .url(myUrl)
        .build()
    // 通过 HttpClient 把 Request 构造为 Call 对象
    val newCall = OkHttpUtils.myHttpClient.newCall(request)

    // 执行异步请求 enqueue
    newCall.enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            println("onFailure $e")
        }

        override fun onResponse(call: Call, response: Response) {
            val body = response.body?.string()
            println("request success $body")
        }
    })

    //在需要的场景上可以通过 Call 对象取消请求
    newCall.cancel()
}

10、拦截器

拦截器可以监控、重写和重试调用。我们可以利用它们在请求发出之前对其进行修改,在响应到达我们的逻辑之前对其进行预处理,或者简单地打印出一些关于请求的细节。

OkHttp有自己实现的日志拦截器。

implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2'
val loggingInterceptor = HttpLoggingInterceptor()
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC)
val okHttpClient = OkHttpClient.Builder()
    .addInterceptor(loggingInterceptor)
    .build()

也可以自己自定义拦截器

val okHttpClient = OkHttpClient.Builder()
    .addInterceptor { chain ->
        val request = chain.request()
        //自定义日志打印
        println("Sending request ${request.url} on ${chain.connection()} ${request.headers}")
        val response = chain.proceed(request)
        //自定义日志打印
        println("Received response for ${response.request.url} ${response.headers}")
        response
    }
    .build()
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值