什么是協(xié)程(Coroutine)
簡單來說散劫,協(xié)程像是輕量級的線程,但并不完全是線程。
首先侮繁,協(xié)程可以讓你順序地寫異步代碼虑粥,極大地降低了異步編程帶來的負(fù)擔(dān);
其次宪哩,協(xié)程更加高效娩贷。多個協(xié)程可以共用一個線程。一個 App 可以運行的線程數(shù)是有限的锁孟,但是可以運行的協(xié)程數(shù)量幾乎是無限的彬祖;
協(xié)程實現(xiàn)的基礎(chǔ)是可中斷的方法(suspending functions)∑烦椋可中斷的方法可以在任意的地方中斷協(xié)程的執(zhí)行储笑,直到該可中斷的方法返回結(jié)果或者執(zhí)行完成。
可中斷的方法(suspending functions) "suspend" 修飾方法
suspend fun suspendingFunction() : Int {
// Long running task
return 0
}
協(xié)程上下文(Coroutine Context)
//運行在UI 線程 圆恤, 這種寫法會造成UI阻塞
CoroutineScope(Dispatchers.Main).launch() {
val datas = RetrofitClient.create(GetDataAPI::class.java).getDatas()
}
//將網(wǎng)絡(luò)請求突倍,文件讀寫等其他方法放在IO線程中
withContext(Dispatchers.IO) {
val datas = RetrofitClient.create(GetDataAPI::class.java).getDatas()
}
//最終寫法
CoroutineScope(Dispatchers.Main).launch() {
withContext(Dispatchers.IO) {
val datas = RetrofitClient.create(GetDataAPI::class.java).getDatas()
}
}
目前為止,我們認(rèn)識了兩個 dispatcher盆昙,下面我們詳細(xì)介紹一下所有的 dispatcher 的使用場景羽历。
Default
當(dāng)我們未指定 dispatcher 的時候會默認(rèn)使用,當(dāng)然淡喜,我們也可以明確設(shè)置使用它秕磷。它一般用于 CPU 密集型的任務(wù),特別是涉及到計算、算法的場景炼团。它可以使用和 CPU 核數(shù)一樣多的線程跳夭。正因為是密集型的任務(wù),同時運行多個線程并沒有意義们镜,因為 CPU 將會很繁忙币叹。
IO
它用于輸入/輸出的場景。通常模狭,涉及到會阻塞線程颈抚,需要等待另一個系統(tǒng)響應(yīng)的任務(wù),比如:網(wǎng)絡(luò)請求嚼鹉、數(shù)據(jù)庫操作贩汉、文件讀寫等,都可以使用它锚赤。因為它不使用 CPU 匹舞,可以同一時間運行多個線程,默認(rèn)是數(shù)量為 64 的線程池线脚。Android App 中有很多網(wǎng)絡(luò)請求的操作赐稽,所以你可能會經(jīng)常用到它叫榕。
UnConfined
如果你不在乎啟動了多少個線程,那么你可以使用它姊舵。它使用的線程是不可控制的晰绎,除非你特別清楚你在做什么,否則不建議使用它括丁。
Main
這是 UI 相關(guān)的協(xié)程庫里面的一個 dispatcher荞下,在 Android 編程中,它使用的是 UI 線程史飞。
協(xié)程構(gòu)造器(Coroutine Builders)
runBlocking
這個協(xié)程構(gòu)造器會阻塞當(dāng)前線程尖昏,直到協(xié)程內(nèi)的所有任務(wù)執(zhí)行完畢。
launch
這個協(xié)程構(gòu)造器很重要构资,因為它可以很輕易地創(chuàng)建一個協(xié)程会宪,你可能會經(jīng)常用到它。和 runBlocking 相反的是蚯窥,它不會阻塞當(dāng)前線程(前提是我們使用了合適的 dispatcher)。
launch 方法會返回一個 Job塞帐,Job 繼承了協(xié)程上下文(CoroutineContext)拦赠。
job.join
將當(dāng)前協(xié)程阻塞執(zhí)行王當(dāng)前異步在按照順序執(zhí)行下一個異步。
job.cancel
這個方法可以取消所有與其關(guān)聯(lián)的子 Job葵姥。也就是相當(dāng)于取消當(dāng)前異步荷鼠。
job.cancel() 是一個普通方法,所以它不必運行在協(xié)程內(nèi)部榔幸。
async
async 允許并行地運行多個子線程任務(wù)允乐,它不是一個可中斷方法,所以當(dāng)調(diào)用 async 啟動子協(xié)程的同時削咆,后面的代碼也會立即執(zhí)行牍疏。async 通常需要運行在另外一個協(xié)程內(nèi)部,它會返回一個特殊的 Job拨齐,叫作 Deferred鳞陨。
Deferred 有一個新的方法叫做 await(),它是一個可中斷的方法瞻惋,當(dāng)我們需要獲取 async 的結(jié)果時厦滤,需要調(diào)用 await() 方法等待結(jié)果。調(diào)用 await() 方法后歼狼,會中斷當(dāng)前協(xié)程掏导,直到其返回結(jié)果。
作用域(Scope)
Global scope
它是一個全局的作用域羽峰,如果協(xié)程的運行周期和 App 的生命周期一樣長的話趟咆,創(chuàng)建協(xié)程的時候可以使用它添瓷。所以它不應(yīng)該和任何可以被銷毀的組件綁定使用。
viewModelScope
這是一個跟ViewModel綁定的作用域忍啸,ViewModel跟Activity/Fragment生命周期綁定仰坦,所以viewModelScope的作用域跟Activity/Fragment生命周期一樣。
回調(diào)方式轉(zhuǎn)為協(xié)程
如果你已經(jīng)考慮將協(xié)程用于現(xiàn)有的項目计雌,你可能會考慮怎么將現(xiàn)有的回調(diào)風(fēng)格的代碼轉(zhuǎn)為協(xié)程:
suspend fun suspendAsyncLogin(username: String, password: String): User =
suspendCancellableCoroutine { continuation ->
userService.doLoginAsync(username, password) { user ->
continuation.resume(user)
}
suspendCancellableCoroutine() 這個方法返回一個 continuation 對象悄晃,continuation 可以用于返回回調(diào)的結(jié)果。只要調(diào)用 continuation.resume() 方法凿滤,這個回調(diào)結(jié)果就可以作為這個可中斷方法的結(jié)果返回給協(xié)程妈橄。
轉(zhuǎn)載自
https://blog.csdn.net/weixin_33701617/article/details/91375647