标题党:一段黄色的代码,Okhttp和Coroutine

黄色的开端

前几天用Okhttp的时候写了一个请求,代码突然变黄了。通常来说会这样写,就算封装也离不开4步

withContext(Dispatchers.IO){
    val client = OkHttpClient.Builder().build()
    val request = Request.Builder().build()
    client.newCall(request).execute()
}
复制代码

但是它突然变黄了

黄色代码

我本以为是IO的警告,加上try、catch还是不行,鼠标一动到黄色位置,提示警告: Inappropriate blocking method call

黄色的原因

不适当的阻塞方法调用

这是什么意思呢?
首先 协程是封装了一套线程池的api,一段协程代码会在一个线程上运行,多段协程代码也有可能在这个线程上运行,充分利用线程。
不适当的阻塞方法调用,也就是说这段代码,对协程可能会有影响,从而导致多个协程任务,在一个线程上运行,变成了 这个任务在一个线程上运行。不完全利用。

探索黄色

okhttp点进去看

  @Throws(IOException::class)
  fun execute(): Response

  fun enqueue(responseCallback: Callback)
复制代码

原来抛出了IOException。

猜想,try、catch不能清除黄色,那么肯定更异常没关系。写了一个方法,修改抛出的异常

@Throws(NullPointerException::class)
fun execute() {
}
复制代码

结果只有IOException会这样。

就4行代码,肯定和协程有关。

既然是协程,又是IO问题,看了一眼IOException类,又点了一下,看看继承IOException,被60多个类继承了。

image.png

看到了SocketException,突然想到,Socket也是一个IO操作,假设Socket连上了,然后阻塞在了这里,如果Socket突然断开了,通常会try、catch,关闭Socket。
那就是说这个http正在请求,进行IO操作,突然断开,只要把请求关了就行。
再换个比方说:

withContext(Dispatchers.IO){
    //...
    IO操作
    //...
}
复制代码

在协程里有个请求,协程不知道它IO操作要多久,假设IO他一直在执行,那协程可能就单独放到一个线程执行,一直阻塞。这不能发挥 协程的 真正作用。所以编译器提示了警告:这个阻塞不太适当

解决黄色

原因:协程认为可能抛出IO异常的代码,可能会一直阻塞,把代码放到线程执行。

协程就是处理耗时任务,只是不想浪费资源。所以 我们期望都在协程上执行。

解决:把代码 丢到一个可取消的协程上执行

val response = suspendCancellableCoroutine<Response> {
    client.newCall(request).execute()
}
复制代码

表示这段代码可以被取消。成功则返回Response,失败则取消这个协程。关于异步同样可以使用call.cancel()

关于

关于我的Httplib,对Okhttp进行了简单的封装。OnceHttp
对于Request进了简单的封装,对于使用者来说,重点关注入参、出参
出参:无非Response.body
入参:key、value的map或者是bean
一个请求:包括host、api、header、body

使用:
使用前配置

ktHttpConfig(this) {
    host = "https://www.wanandroid.com/"
    //公共的 header参数
    header["appVersion"] = "1.0.0"
    //公共的 body参数
    //mapData["appVersion"] = "1.0.0"
    //可以传入一个client
    //okHttpClient = OkHttpClient.Builder().build()
}
复制代码

请求继承 OnceRequest() 就好,api、header、body可以自由更改

OnceRequest,增加了两个拦截的方法

//请求之前 修改 请求的数据
open fun beforeRequest(map:MutableMap<String,String>) = mapData
//请求之后 修改 返回的数据
open fun <T> afterRequest(bean:T) : T = bean
复制代码

在一次请求前,修改参数,在请求后,修改返回的数据。(比如:请求其他服务器,加密解密方式不同)

也提供了3种数据返回方式

requestBackLiveData(): LiveData<T> 
requestBackFlow(): Flow<T>
requestBackBean():T
复制代码

内容较多,不是很完善,持续更新中

如果感觉本文内容对你有帮助的话,麻烦点个赞。

如果内容有错误,我及时更改。

Guess you like

Origin juejin.im/post/7059279388923133959