官方介紹協(xié)程
協(xié)程定義
協(xié)程定義:kotlin官方基于JVM的線程實(shí)現(xiàn)的一個(gè)并發(fā)任務(wù)處理框架,封裝的線程api
- 使用方便,不使用回調(diào)實(shí)現(xiàn)線程切換,使用同步方式寫(xiě)出異步代碼
- 所有的耗時(shí)任務(wù)保證一定放在后臺(tái)執(zhí)行
- 掛起函數(shù)執(zhí)行完畢之后,協(xié)程會(huì)把它切換到原先的線程的線程。
協(xié)程的基本用法
常規(guī)函數(shù)中一般都有:call and return,協(xié)程在此之外添加了suspend和resume.
- suspend 用于暫停執(zhí)行的當(dāng)前協(xié)程,并保存所有的局部變量
- resume 用于已暫停的協(xié)程中暫停出恢復(fù)
supend(掛起函數(shù))是什么,有什么意義
suspend,對(duì)協(xié)程的掛起并沒(méi)有實(shí)際作用,其實(shí)只是一個(gè)提醒,函數(shù)創(chuàng)建者對(duì)函數(shù)的調(diào)用者的提醒,提醒調(diào)用者我是需要耗時(shí)操作,需要用掛起的方式,在協(xié)程中使用.
- 需要注意的是掛起函數(shù)只能在掛起函數(shù)或者協(xié)程作用域中使用,為什么掛起函數(shù)需要在協(xié)程作用域中使用?因?yàn)槠胀ê瘮?shù)沒(méi)有suspend和resume這兩個(gè)特性,所以必須要在協(xié)程的作用中使用。
意義:
語(yǔ)法層面:作為一個(gè)標(biāo)記和提醒。通過(guò)報(bào)錯(cuò)來(lái)提醒調(diào)用者和編譯器,這是一個(gè)耗時(shí)函數(shù),需要放在后臺(tái)執(zhí)行。
編譯器層面:輔助 Kotlin 編譯器來(lái)把代碼轉(zhuǎn)換成 JVM 的字節(jié)碼。
怎么自定義suspend函數(shù)?
- 什么時(shí)候定義?
需要耗時(shí)操作的時(shí)候,需要定義,例如io耗時(shí)操作(請(qǐng)求網(wǎng)絡(luò));獲取數(shù)據(jù)庫(kù)數(shù)據(jù);一些等待一會(huì)需要的操作;列表排除,json解析等;
- 怎么寫(xiě)suspend函數(shù)
給函數(shù)前加上suspend 關(guān)鍵字,把內(nèi)容用withContext包起來(lái)
suspend fun testSuspendfun(){
withContext(Dispatchers.IO){
}
}
協(xié)程如何確保主線程安全
- Dispatchers.Main 調(diào)用程序在Android的主線程中
- Dispatchers.IO 適合主線程之外的執(zhí)行磁盤(pán)或者網(wǎng)絡(luò)io操作,例如文件的讀取與寫(xiě)入,任何的網(wǎng)絡(luò)請(qǐng)求
- Dispatcher.Default 適合主線程之外的,cpu的操作,例如json數(shù)據(jù)的解析,以及列表的排序,
協(xié)程的掛起本質(zhì)
- 本質(zhì)就是切線程,完成之后只不過(guò)可以自動(dòng)切回來(lái)
協(xié)程掛起就是切個(gè)線程,在掛起函數(shù)執(zhí)行完畢之后,協(xié)程會(huì)自動(dòng)的重新切回它原先的線程,也就是稍后會(huì)被切回來(lái)的線程切換。切回來(lái)就是resume,恢復(fù)功能是協(xié)程,所以suspend函數(shù)需要在另一個(gè)suspend函數(shù)或者協(xié)程中調(diào)用.
- 什么是協(xié)程的「非阻塞式掛起」
阻塞的方式寫(xiě)出了非阻塞的方式
協(xié)程的創(chuàng)建以及取消
//創(chuàng)建一個(gè)協(xié)程
Val scope = CoroutineScope(Dispatchers.Main+Job())
通過(guò)Job獲取協(xié)程的生命周期
scope.launch{
}
其他耗時(shí)請(qǐng)求,例如從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù)
scope.async {
}
在KTX庫(kù)為某些生命周期提供自己的CoroutineScope,例如ViewModel中viewModelScope,Lifecycle有l(wèi)ifecycleScope
協(xié)程的啟動(dòng)
- launch 啟動(dòng)新協(xié)程而不將結(jié)果返回給調(diào)用方
//創(chuàng)建之后,不管后續(xù)
launch(){
}
- async 啟動(dòng)一個(gè)新協(xié)程,并通過(guò)deferred的await方法暫停函數(shù)
//返回deferred 對(duì)象
val deferred async{
}
deferred.await()
協(xié)程的結(jié)構(gòu)化并發(fā),取消協(xié)程
協(xié)程的結(jié)構(gòu)化并發(fā),可以讓協(xié)程非常便于管理。例如在關(guān)閉activity中要取消協(xié)程。如果是在線程中,取消所有的線程比較復(fù)雜。
- 取消父協(xié)程以及父里面的子協(xié)程
val scope = CoroutineScope(Dispatchers.Main+ Job())
scope.launch {
val job = launch {
val job1 = launch {
}
}
job.cancel()
}
scope.cancel()
- 取消子協(xié)程某一個(gè)
每一個(gè)協(xié)程都會(huì)返回一個(gè)job對(duì)象,通過(guò)調(diào)用job的cancle,可以去取消單個(gè)的協(xié)程的。
val scope = CoroutineScope(Dispatchers.Main+ Job())
scope.launch {
val job = launch {
val job1 = launch {
}
}
job.cancel()
}
scope.cancel()
協(xié)程中異常處理
- 在協(xié)程內(nèi)部中捕獲異常
val scope = CoroutineScope(Dispatchers.Main+ Job())
scope.launch {
try {
}catch (e:Exception){
}
}