美文网首页
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