6.协程的挂起

挂起函数的作用以及使用场景:
挂起函数会让协程从正在执行它的线程上脱离,并在挂起函数执行结束恢复到原线程,实现非阻塞式挂起。
可用于耗时的函数比如联网获取数据,数据库读写,文件io等
1.标准挂起函数应该定义线程切换,取消机制,结果返回三个部分
retrofit2.7.1里面部分源码KotlinExtensions.class

@JvmName("awaitNullable")
suspend fun  Call.await(): T? {
  return suspendCancellableCoroutine { continuation ->
    continuation.invokeOnCancellation {
      cancel()
    }
    enqueue(object : Callback {
      override fun onResponse(call: Call, response: Response) {
        if (response.isSuccessful) {
          continuation.resume(response.body())
        } else {
          continuation.resumeWithException(HttpException(response))
        }
      }

      override fun onFailure(call: Call, t: Throwable) {
        continuation.resumeWithException(t)
      }
    })
  }
}

2.如何自定义挂起函数
仅仅依靠suspend修饰符是改变不了线程的

suspend fun getUser():String{
    log("getUser")
    return ""
}
suspend fun main(){
    getUser()
}

打印:

16:07:05:167 [main,1] getUser

示例1 只有返回值跟切换线程

suspend fun getUserInIo()= withContext(Dispatchers.IO){
    "hhahah"
}
suspend fun main(){
    GlobalScope.launch {
        val userInIo = getUserInIo()
        log(userInIo)
    }.join()
}

打印:

16:23:50:267 [DefaultDispatcher-worker-3,14] hhahah

示例 不做线程切换,依靠协程做切换

suspend fun getUser1()= suspendCoroutine {
    //直接使用当前协程所在的线程,不做切换
    it.resume("hhahahah")
}
suspend fun main(){
    val user1 = getUser1()
    log(user1)
    GlobalScope.launch {
        log(1)
        val user11 = getUser1()
        log(user1)
        withContext(Dispatchers.IO){
            val user11 = getUser1()
            log(user1)
        }
    }.join()
}

示例
既做线程切换,又有取消

suspend fun getUserInFile()= suspendCancellableCoroutine {
    var threadStop=true
    it.invokeOnCancellation {
        //如果没有这个,那么挂起函数是无法取消的
        threadStop=false
    }
    thread (name = "hahaha"){
        //模拟耗时操作
        try {
            var i=0;
            while (threadStop&&i<1000){
                Thread.sleep(100)
                i++
                log(i)
            }
            it.resume(i)
        }catch (e: Exception){
            it.resumeWithException(e)
        }
    }
}
suspend fun main(){
    val launch = GlobalScope.launch{
        log("start")
        val userInFile = getUserInFile()
        log(userInFile)
    }
    delay(1000)
    launch.cancel()
    delay(1000)
}

你可能感兴趣的:(6.协程的挂起)