OkHttp的基本用法

QuibblerQuibbler 2021-03-10 约 16 分钟 2287 次阅读

OkHttp的基本用法

看完Google官方的网络通信库Volley,再继续学习Android开发中大名鼎鼎的网络请求框架:OkHttp。深入学习一个优秀的框架之前,先了解它的基本用法,由浅入深,逐步探索。本篇简要介绍一下OkHttp的使用,关于拦截器详见OkHttp拦截器Interceptor。

1、OkHttp

OkHttp是Square公司开源的网络请求框架,Android开发中另一个网络请求框架Retrofit就是基于OkHttp二次封装。

1.1、介绍

OkHttp是一个支持HTTP 和 HTTP/2 的客户端,可以在Android和Java应用程序中使用,其具有以下特点:

        1. API设计轻巧,基本上通过几行代码的链式调用即可获取结果。

        2. 既支持同步请求,也支持异步请求。同步请求会阻塞当前线程,异步请求不会阻塞当前线程,异步执行完成后执行相应的回调方法。

        3. 其支持HTTP/2协议,通过HTTP/2,可以让客户端中到同一服务器的所有请求共用同一个Socket连接。

        4. 如果请求不支持HTTP/2协议,那么Okhttp会在内部维护一个连接池, 通过该连接池,可以对HTTP/1.x的连接进行重用,减少了延迟。

        5. 透明的GZIP处理降低了下载数据的大小。

        6. 请求的数据会进行相应的缓存处理,下次再进行请求时,如果服务器告知304(表明数据没有发生变化),那么就直接从缓存中读取数据,降低了重复请求的数量。

其它废话就不多粘贴了,详见官方文档:

官方指南:OkHttp Overview

GitHub:square/okhttp

1.2、准备

在模块的build.gradle中添加OkHttp依赖,用最新的稳定版本,开源库的查找参考添加三方开源库的正确方式一文。

//OkHttp
    implementation 'com.squareup.okhttp3:okhttp:4.9.1'

使用网络别忘了在AndroidManifest.xml中添加应用网络访问权限,这是新手容易忽略的小坑。

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

接下来开始了解OkHttp最常用的两种请求:GET请求和POST请求。

2、GET请求

网络请求通过OkHttp提供的OkHttpClient发起,先创建一个OkHttpClient实例。这里展示用法,实际项目中不要创建多个OkHttpClient实例(应使用单例)。

//直接创建默认OkHttpClient
    val okHttpClient: OkHttpClient = OkHttpClient()
    
    //使用OkHttpClient.Builder构造
    val okHttpClient: OkHttpClient = OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .build()

2.1、构造Request

使用Request的内部类Builder构造网络请求,Request默认请求方法是GET,可以调用get()或者method("GET" , requestBody)方法设置请求为GET。

//网络请求Request通过内部类Request.Builder建造者模式创建
    val requestBuilder: Request.Builder = Request.Builder()
    requestBuilder.url(url)
    
    //请求方法设置为GET,RequestBody请求体空。也可用get()进行设置,内部实现是一样的
    requestBuilder.method("GET", null)
    
    //从Request.Builder创建Request实例
    val request: Request = requestBuilder.build()

OkHttp中很多类的实例(比如:FormBody、MultipartBody、Headers等)都是通过内部Builder类构造。本篇只简单了解一下,后面会专门深入源码研究。

2.2、准备请求Call

借助本节开头创建的OkHttpClient实例,调用newCall(Request )方法获取网络请求Call接口类型的实例,每个Call实例代表单个响应流,只能执行一次请求,实现类是RealCall。

//通过第一步创建的OkHttppClient创建网络Call对象
    val call: Call = okHttpClient.newCall(request)

通过Call发起最终网络请求,有两种方式:异步enqueue(Callback)和同步的execute()。

2.3、异步GET:enqueue()

拿到已准备好执行的请求Call,调用enqueue(Callback)方法提交异步网络请求。请求会被放到OkHttpClient的Dispatcher中调度执行,网络请求完之后后执行Callback回调。

//调用Call的enqueue(Callback )方法异步请求,在回调中处理网络请求结果
    call.enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            //网络请求失败回调
        }
        override fun onResponse(call: Call, response: Response) {
            //处理网络请求响应
        }
    })

2.4、同步GET:execute()

同步的网络请求必须在子线程中进行,因为是耗时的网络操作。执行请求Call的execute()方法获取网络请求返回的结果Response。

//调用Call的execute()方法同步请求,获取返回的Response
    Thread {
        try {
            call.execute().use {
                //处理网络结果Response
                val data = it.body
            }
        } catch (e: Exception) {
            Log.e(TAG, "${e.message}")
        }
    }.start()

使用完要关闭Response避免内存泄漏,这里使用Closeable的扩展函数use{},方法执行完后自动关闭资源。

3、POST请求

POST提交请求和GET差不多,POST请求需要了解RequestBody的构造,POST请求携带不同的RequestBody以上传不同的数据内容给服务端。在这节简单了解一下RequestBody请求体,关于OkHttp的RequestBody详见OkHttp之RequestBody请求体。

3.1、RequestBody

POST向服务端提交数据,离不开网络请求的数据载体:RequestBody。在该抽象类中使用Kotlin实现了很多扩展方法方便开发者从String、File、ByteArray中创建RequestBody实例。

抽象类RequestBody有两个实现类:FormBody和MultipartBody,方便开发者提交表单数据和分块数据。

3.2、POST文本

从String文本直接通过扩展函数toRequestBody(MediaType )构造RequestBody,传入MediaType指明数据内容的MIME类型。关于MIME详见了解媒体类型MIME。

//创建数据的MIME类型,关于MIME参考另一博客
    val stringMediaType: MediaType = "text/plain".toMediaType()
    //直接通过String扩展函数构造对应的RequestBody
    val stringRequestBody: RequestBody = "string from client".toRequestBody(stringMediaType)
    
    //简单快速的构造一个文本POST请求
    val request: Request = Request.Builder()
        .url(url)
        .post(stringRequestBody)
        .build()
    val call: Call = client.newCall(request)
    
    //处理POST
    try {
        call.execute().use {
        }
    } catch (e: Exception) {
    }

3.3、POST表单

通过FormBody内部Builder类构造表单,携带key-value表单数据。

val requestBodyBuilder: FormBody.Builder = FormBody.Builder()
    requestBodyBuilder.add("keywords", "search")
    
    val requestBody: RequestBody = requestBodyBuilder.build()

Request.Builder构造POST请求,调用post(Request )或method("POST", Request)将请求方法设置为POST。

val requestBuilder: Request.Builder = Request.Builder()
    requestBuilder.url(url)
                  .method("POST", requestBody)  //和下面方法等价
                  .post(requestBody)            //和上面方法等价

发起POST请求和GET方式一样,至于异步或同步看具体业务场景。

try {
        call.execute().use {
            //表单提交完成
        }
    } catch (e: Exception) {
        //表单提交异常
    }

3.4、POST上传文件

上传文件也很简单,借助RequestBody内部实现的File扩展函数asRequestBody(),从文件对象直接创建对应的RequestBody。发起上传文件的请求和上一节的POST流程一样。

//指明文件MIME为图片image/png
    val fileContentType: MediaType? = "image/png".toMediaTypeOrNull()
    
    //从File创建RequestBody
    val fileBody = File(path).asRequestBody(fileContentType)
    
    //构造文件上传请求
    val request: Request = Request.Builder()
            .url(url)
            .post(fileBody)
            .build()
    
    //同步执行文件上传请求
    val call: Call = OkHttpClient().newCall(request)
    try {
        call.execute().use {
            //表单提交异常
        }
    } catch (e: Exception) {
        //表单提交异常
    }

3.5、Multipart分块POST

借助OkHttp内部的MultipartBody类可以构造复杂的请求体。分块请求体中的每块都是独立的一个RequestBody,可以设置自己的Header。

//通过MultipartBody.Builder构造
    val multipartBodyBuilder: MultipartBody.Builder = MultipartBody.Builder()
    multipartBodyBuilder.setType("multipart/form-data".toMediaType())
    
    //添加分块
    multipartBodyBuilder.addPart(requestOne)
    multipartBodyBuilder.addPart(MultipartBody.Part.create(requestTwo))
    multipartBodyBuilder.addPart(MultipartBody.Part.create(null, requestTwo))
    multipartBodyBuilder.addPart(Headers.headersOf("key", "value"), requestThree)
    
    //build()分块请求体对象
    val multipartBody: MultipartBody = multipartBodyBuilder.build()

相关推荐

精选
Airbnb开源项目
开源

Airbnb开源项目

Airbnb Engineering & Data ScienceAirflow Use Apache Airflow (incubating) to author workflows as directed acyclic graphs (DAGs) of tasks12,263Airpal Web UI for PrestoDB2,502Aerosolve A machine learning

1.8k
OkHttp线程池和连接池
开源

OkHttp线程池和连接池

OkHttp线程池和连接池了解了OkHttp的网络请求流程以及拦截器实现原理,再关注OkHttp中两个重要的:OkHttp的线程池和连接池。1、OkHttp线程池在OkHttp网络请求流程一文中,我们分析了OkHttp异步和同步请求流程。请求最后都在Dispatcher中分发调度处理,最后被ExecutorService执行。1.1、DispatcherDispatcher中执行任务的执行器是ex

5.2k
优美的开源动效库:Lottie
开源

优美的开源动效库:Lottie

优美的开源动效库:Lottie1、强大的动效LottieLottie是一个适用于Android,iOS,Web和Windows的库,它可以使用Bodymovin解析以json格式导出的Adobe After Effects动画,并在移动设备和Web上原生渲染它们!GitHub:https://github.com/airbnb/lottie-androidLottie官网:http://airbn

4.3k