掛起函數(shù)的作用以及使用場景:
掛起函數(shù)會讓協(xié)程從正在執(zhí)行它的線程上脫離,并在掛起函數(shù)執(zhí)行結(jié)束恢復(fù)到原線程,實現(xiàn)非阻塞式掛起。
可用于耗時的函數(shù)比如聯(lián)網(wǎng)獲取數(shù)據(jù),數(shù)據(jù)庫讀寫,文件io等
1.標(biāo)準(zhǔn)掛起函數(shù)應(yīng)該定義線程切換,取消機制,結(jié)果返回三個部分
retrofit2.7.1里面部分源碼KotlinExtensions.class
@JvmName("awaitNullable")
suspend fun <T : Any> Call<T?>.await(): T? {
return suspendCancellableCoroutine { continuation ->
continuation.invokeOnCancellation {
cancel()
}
enqueue(object : Callback<T?> {
override fun onResponse(call: Call<T?>, response: Response<T?>) {
if (response.isSuccessful) {
continuation.resume(response.body())
} else {
continuation.resumeWithException(HttpException(response))
}
}
override fun onFailure(call: Call<T?>, t: Throwable) {
continuation.resumeWithException(t)
}
})
}
}
2.如何自定義掛起函數(shù)
僅僅依靠suspend修飾符是改變不了線程的
suspend fun getUser():String{
log("getUser")
return ""
}
suspend fun main(){
getUser()
}
打?。?/p>
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
示例 不做線程切換,依靠協(xié)程做切換
suspend fun getUser1()= suspendCoroutine<String> {
//直接使用當(dāng)前協(xié)程所在的線程,不做切換
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<Int> {
var threadStop=true
it.invokeOnCancellation {
//如果沒有這個,那么掛起函數(shù)是無法取消的
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)
}