美文网首页
Kevin Learn Kotlin:网络编程(okhttp)

Kevin Learn Kotlin:网络编程(okhttp)

作者: Kevin_小飞象 | 来源:发表于2021-12-16 14:18 被阅读0次
    12.jpg

    okhttp

    31.png

    okhttp 是一个高效的 HTTP 客户端,它的横空出世,让其他的网络请求框架都变得黯然失色。

    背景

    在 okhttp 出现以前,Android 发起网络请求要么使用系统自带的 HttpClient 、HtttpURLConnection ;要么使用 Google 开源的 Volley ; 要么使用第三方开源的 AsyncHttpClient 等等。
    目前大量流行库都以 okhttp 作为底层网络请求框架或提供支持,比如:Retrofit、Glide、Fresco、Moshi、Picasso 等。

    特点

    • 同时支持 Http1.1 和 Http2.0
    • 同时支持同步与异步请求;
    • 同时具备 Http 与 WebSocket 功能;
    • 拥有自动维护的 socket 连接池,减少握手次数;
    • 拥有队列线程池,轻松写并发;
    • 拥有 Interceptors(拦截器),轻松处理请求与响应额外需求。

    开始使用

    1. 在 AndroidManifest.xml 中添加网络访问权限:
    <uses-permission android:name="android.permission.INTERNET"/>
    
    1. 在 app/build.gradle 的 dependencies 中添加如下依赖:
    implementation("com.squareup.okhttp3:okhttp:4.9.3")
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.3")
    
    1. 初始化
    import okhttp3.OkHttpClient
    import java.util.concurrent.TimeUnit
    
    /**
     * Created on 2021/12/16 10:02
     *
     * @author Gong Youqiang
     */
    object BaseOkHttp {
        val client = OkHttpClient.Builder()
            .connectTimeout(10,TimeUnit.SECONDS)
            .readTimeout(10,TimeUnit.SECONDS)
            .writeTimeout(10,TimeUnit.SECONDS)
            .build()
    }
    

    GET 请求

    同步 GET 请求

    同步 GET 请求是指一直等待 http 请求,直到返回了响应。在这之间会阻塞线程,所以同步请求不能在 Android 的主线程中执行,否则会报 NetworkMainThreadException.

    object BaseOkHttp {
        private const val TAG = "BaseOkHttp"
        // 1. 创建 OkHttpClient 实例 client 
        val client = OkHttpClient.Builder()
            .connectTimeout(10,TimeUnit.SECONDS)
            .readTimeout(10,TimeUnit.SECONDS)
            .writeTimeout(10,TimeUnit.SECONDS)
            .build()
    
        fun get(url:String) {
            Thread(Runnable {
                // 2. 通过 Request.Builder() 构建一个 Request 请求实例 request
                val request:Request = Request.Builder()
                    .url(url)
                    .build()
    
                // 3. 通过 client.newCall(request) 创建一个 Call 实例
                val call = client.newCall(request)
    
                // 4. Call 的实例调用 execute 方法发送同步请求
                val response = call.execute()
                val body = response.body?.string()
    
                // 5. 请求返回的 response 转换为 String 类型返回
                Log.e(TAG,"get response : ${body}")
            }).start()
        }
    }
    

    异步 GET 请求

    异步 GET 请求是指在另外的工作线程中执行 http 请求,请求时不会阻塞当前的线程,所以可以在 Android 主线程中使用。

    /**
     * Created on 2021/12/16 10:02
     *
     * @author Gong Youqiang
     */
    object BaseOkHttp {
        private const val TAG = "BaseOkHttp"
        val client = OkHttpClient.Builder()
            .connectTimeout(10,TimeUnit.SECONDS)
            .readTimeout(10,TimeUnit.SECONDS)
            .writeTimeout(10,TimeUnit.SECONDS)
            .build()
    
      
        fun getAsync(url:String) {
            // 构造请求体
            val request:Request = Request.Builder()
                .url(url)
                .build()
    
            // 构造请求对象
            val call = client.newCall(request)
    
            // 发起异步请求 enqueue
            call.enqueue(object :Callback{
                override fun onResponse(call: Call, response: Response) {
                    val body = response.body?.string()
                    Log.e(TAG,"get response : ${body}")
                }
                
                override fun onFailure(call: Call, e: IOException) {
                    Log.e(TAG,"get response failure : ${e.message}")
                }
            })
        }
    }
    

    说明:无论是同步还是异步请求,接收到的 response 结果都是在子线程中,onResponse、onFailure 的回调是在子线程中的,我们需要切换到主线程才能操作 UI 控件。

    POST 请求

    同步 POST 请求

    /**
     * Created on 2021/12/16 10:02
     *
     * @author Gong Youqiang
     */
    object BaseOkHttp {
        // 注意该URL 是笔者本地服务器地址
        private const val BASE_URL = "http://192.168.10.62:8082/HKservice"
        private const val TAG = "BaseOkHttp"
        val client = OkHttpClient.Builder()
            .connectTimeout(10,TimeUnit.SECONDS)
            .readTimeout(10,TimeUnit.SECONDS)
            .writeTimeout(10,TimeUnit.SECONDS)
            .build()
    
      
        fun post() {
            val body:FormBody = FormBody.Builder()
                .add("id","35")
                .add("status","进行中")
                .build()
    
            val request = Request.Builder()
                .url("$BASE_URL/record/updateStatus")
                .post(body)
                .build()
    
            val call = client.newCall(request)
    
            Thread(Runnable {
                val response = call.execute()
                Log.e(TAG, "post response:${response.body?.string()}")
            }).start()
    
        }
    }
    

    异步 POST 请求

    /**
     * Created on 2021/12/16 10:02
     *
     * @author Gong Youqiang
     */
    object BaseOkHttp {
        // 注意该URL 是笔者本地服务器地址
        private const val BASE_URL = "http://192.168.10.62:8082/HKservice"
        private const val TAG = "BaseOkHttp"
        val client = OkHttpClient.Builder()
            .connectTimeout(10,TimeUnit.SECONDS)
            .readTimeout(10,TimeUnit.SECONDS)
            .writeTimeout(10,TimeUnit.SECONDS)
            .build()
    
        fun postAsync() {
            val body:FormBody = FormBody.Builder()
                .add("id","35")
                .add("status","进行中")
                .build()
    
            val request = Request.Builder()
                .url("$BASE_URL/record/updateStatus")
                .post(body)
                .build()
    
            val call = client.newCall(request)
    
            call.enqueue(object : Callback{
                override fun onResponse(call: Call, response: Response) {
                    Log.e(TAG, "post response:${response.body?.string()}")
                }
                
                override fun onFailure(call: Call, e: IOException) {
                    Log.e(TAG, "post failure:${e.message}")
                }
            })
        }
    }
    

    拦截器 LoggingInterceptor

    作用
    它是 OkHttp 中一个比较强大的机制,可以监视、重写和重试调用请求。
    简单使用(自定义)

    /**
     * Created on 2021/12/16 13:38
     *
     * @author Gong Youqiang
     */
    class LoggingInterceptor : Interceptor {
        private val TAG = "OkHttp"
    
        override fun intercept(chain: Interceptor.Chain): Response {
            val time_start = System.nanoTime()
            val request = chain.request()
            val response = chain.proceed(request)
    
            val buffer = Buffer()
            request.body?.writeTo(buffer)
            val requestBodyStr = buffer.readUtf8()
            Log.e(TAG, String.format("Sending request %s with params %s",request.url,requestBodyStr))
    
            val bussinessData = response.body?.string()?:"response body null"
            val mediaType = response.body?.contentType()
            val newBody = ResponseBody.create(mediaType,bussinessData)
            val newResponse = response.newBuilder().body(newBody).build()
    
            val time_end = System.nanoTime()
            Log.e(TAG, String.format(
                "Received response for %s in %.1ms >>> %s",
                request.url,
                (time_end - time_start) / 1e6,
                bussinessData
            ))
            return newResponse
        }
    }
    

    使用自带的

    /**
     * Created on 2021/12/16 10:02
     *
     * @author Gong Youqiang
     */
    object BaseOkHttp {
        private const val BASE_URL = "http://192.168.10.62:8082/HKservice"
        private const val TAG = "BaseOkHttp"
        private val client:OkHttpClient
        init {
            val httpLoggingInterceptor = HttpLoggingInterceptor()
            httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY)
    
            client = OkHttpClient.Builder()
                .connectTimeout(10,TimeUnit.SECONDS)
                .readTimeout(10,TimeUnit.SECONDS)
                .writeTimeout(10,TimeUnit.SECONDS)
                .addInterceptor(httpLoggingInterceptor)
                .build()
        }
    
        fun get(url:String) {
            Thread(Runnable {
                // 构造请求体
                val request:Request = Request.Builder()
                    .url(url)
                    .build()
    
                // 构造请求对象
                val call = client.newCall(request)
    
                // 发起同步请求 execute
                val response = call.execute()
                val body = response.body?.string()
    
                Log.e(TAG,"get response : ${body}")
            }).start()
        }
    }
    

    相关文章

      网友评论

          本文标题:Kevin Learn Kotlin:网络编程(okhttp)

          本文链接:https://www.haomeiwen.com/subject/ctgmfrtx.html