程序员AndroidAndroid开发

Android OKHttp的基本使用

2020-12-02  本文已影响0人  JingChen_

一、

Android中网络请求是必不可少的。OkHttp是网络框架界的大佬了,很多网络框架都基于OkHttp封装。本章主要讲OKHttp的使用,后面会写到用它封装的其他框架的使用。

需在 build.gradle 里面加入依赖

implementation 'com.squareup.okhttp3:okhttp:4.3.1'

二、

由于网络请求是耗时操作,在UI线程中,请求超过5s会导致应用无响应(ANR),所以Android规定了网络请求只能在子线程里面完成。

同步请求和异步请求

在Http中,请求的方式有两种:GET 和 POST。请求分为同步请求和异步请求。GET 和 POST 的差别在于有无请求体。先来看看同步和异步的区别。(以GET请求为例)

① 同步网络请求:需要在子线程中执行,而处理的UI需要回到UI线程中处理。

    private fun getSyncOkHttp() {
        //子线程
        thread {
            //请求参数
            val request = Request.Builder()
                .url("http://www.baidu.com")
                .build()
            //客户端
            val client = OkHttpClient.Builder()  
                .build()
            //调用execute()为同步请求并返回Response对象
            response = client.newCall(request).execute()
            //判断时候请求成功
            response?.isSuccessful?.apply {
                if (this) {
                    runOnUiThread {
                        text1.text = response?.message
                    }
                }
            }
        }
    }

同步网络请求的标志:execute()。假如得到结果后要对UI进行操作,需要切换到主线程。

② 异步网络请求:不需要在子线程了,但回调方法是执行在子线程中,所以在更新UI时还要跳转到UI线程中,跟同步请求切换线程一样。

    private fun getAsyncOkHttp() {
        //请求参数
        val request = Request.Builder()
            .url("http://www.baidu.com")
            .build()

        //客户端
        val client = OkHttpClient.Builder()
            .build()
        //调用enqueue()为异步请求并回调到子线程
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {

            }
            //请求成功
            override fun onResponse(call: Call, response: Response) {
                //切换到UI线程
                runOnUiThread { 
                    text1.text = response.message
                }
            }
        })
    }

异步网络请求的标志:enqueue()。假如得到结果后要对UI进行操作,需要切换到主线程。

首先,我们要建立一个客户端client,用于发送请求参数request,再把所需要的数据添加到request,如url、请求头header...,然后用client调用newCall方法,把请求参数传进去,最后调用execute()或者enqueue()得到回调结果并做一系列处理。

再来看下POST请求(以异步请求为例):

    private fun postAsyncOkHttp() {
        //请求体(传输表单类型)
        val mBody = FormBody.Builder()
            .build()

        //请求参数
        val request = Request.Builder()
            .url("http://www.baidu.com")
            .post(mBody)
            .build()

        //客户端
        val client = OkHttpClient.Builder()
            .build()

        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {
            }

            override fun onResponse(call: Call, response: Response) {
                runOnUiThread {
                    text1.text = response.message
                }
            }
        })
    }

与GET方式不同的是,要在请求参数里面加个请求体,request里面用post()接受一个RequestBody对象,RequestBody是一个抽象类,分别有FormBody和MultipartBody两个子类,上面这个例子使用的是FormBody,用于传输表单类型的参数。MultipartBody则支持多类型的参数传递,例如:在传输表单类型的参数的同时,还是可以传输文件。创建一个MultipartBody对象再调用post()方法就OK了。

在Request.Builder中如果调用post方法则把请求方式设为POST,否则默认为GET。与GET相比,POST需要有请求体接收,其他都与GET相同。

请求头

刚才有提到请求头Header,它是通过Request.Builder对象的相关方法来维护的,如下:

① headers(Headers headers)
② header(String name, String value)
③ addHeader(String name, String value)
④ removeHeader(String name)

addHeader和removeHeader方法,分别是添加和移除header信息。header(String name, String value)这是会重新设置指定name的header信息。headers(Headers headers)则是会移除掉原有的所有header信息,将参数headers的header信息添加到请求中。

注:header和addHeader的区别:指定name如果存在的话,那么header会重新设定name的value,如果不存在,header和addHeader一样是添加头信息。

        //请求参数
        val request = Request.Builder()
            .addHeader("Charset","UTF-8")
            .url("http://www.baidu.com")
            .build()

超时时间

在网络请求的客户端中,我们可以设定请求的超时时间,包括连接,调用和读写时间,在OKHttpClient.Builder里面设定的,假如不设定,将使用默认的超时设置。

        val timeOut:Long = 15   //超时时间
        //客户端
        val client = OkHttpClient.Builder()
            .connectTimeout(timeOut, TimeUnit.SECONDS)
            .readTimeout(timeOut, TimeUnit.SECONDS)
            .writeTimeout(timeOut, TimeUnit.SECONDS)
            .build()

其中第一个参数是超时时间,第二个参数是超时时间单位。

拦截器(Interceptor)

拦截器在OKHttp里面的作用还是非常强大的,能够监视请求,例如在拦截器中设定请求发送和响应的一些信息输出操作,还可以重写请求信息,例如修改url、添加请求头header...

拦截器还分为两种:
① 网络拦截器
② 应用拦截器

首先创建个拦截器继承Interceptor接口,复写Intercept方法。其中,chain可以去到你想要的数据,例如chain.request()能去到当前的请求体,chain.url能去到当前的url...就是说,请求经过一系列操作后来到拦截器,拦截器能得到请求的东西并能对其进行操作,最后调用chain.proceed()方法把响应结果返回出去。

    private fun getAsyncOkHttp() {
        //请求参数
        val request = Request.Builder()
            .url("http://www.baidu.com")
            .build()

        //客户端
        val client = OkHttpClient.Builder()
            .addInterceptor(MyInterceptor())
            .build()
        //调用enqueue()为异步请求并回调到子线程
        client.newCall(request).enqueue(object : Callback {
            override fun onFailure(call: Call, e: IOException) {

            }
            //请求成功
            override fun onResponse(call: Call, response: Response) {
                //切换到UI线程
                runOnUiThread { 
                    Log.e("Interceptor",response.url.toString())
                }
            }
        })
    }

    private class MyInterceptor:Interceptor{
        override fun intercept(chain: Interceptor.Chain): Response {
            val oldRequest = chain.request()
            val newRequest = oldRequest.newBuilder()
                .url("http://www.google.com")
                .build()
            return chain.proceed(newRequest)
        }
    }

在原来的client中添加了拦截器,拦截器中先去到原来的请求体,得到oldRequest,再调用newBuilder()方法对其进行重构,可以加一些请求头信息,或者更改url...之后把定义好的newRequest通过chain.proceed()得到新的response返回出去。其中,chain.proceed()是真正发生网络请求的地方。运行结果打印出之后设定的url:"http://www.google.com"

注:拦截器可以设置多个,并且拦截器的调用是有顺序的。例如进去A拦截器出来后,再进入B拦截器时,请求体与刚进去A拦截器是有所不同的。

之前还写过一篇用拦截器更改baseUrl的操作的文章,感兴趣的同学可以看看。

三、

OKHttp的使用基本就这些了,如果想更加深入可以看看源码,学习时请求顺序不要乱就好了,记得请求头、超时时间设置及拦截器分别再那些地方加上去,初学者很容易混淆的,包括我 - -!

后面会继续写OKHttp+Retrofit的配合使用。文章有写的不好的地方麻烦大伙提出来,感谢~

上一篇下一篇

猜你喜欢

热点阅读