一、開啟協(xié)程的方式
- 使用 runBlocking 頂層函數(shù)。它會 在協(xié)程作用域內(nèi)的所有代碼和子協(xié)程沒有全部執(zhí)行完成之前 一直阻塞當(dāng)前線程。一般在測試環(huán)境中使用。
runBlocking {
}
- 使用 GlobalScope 單例對象。也是頂層協(xié)程。不推薦使用。
GlobalScope.launch {
}
- 創(chuàng)建 CoroutineScope 對象。CoroutineScope()是一個(gè)函數(shù),會返回一個(gè)CoroutineScope對象。之后調(diào)用它的launch函數(shù)就可以創(chuàng)建一個(gè)協(xié)程。
CoroutineScope(Dispatchers.XX).launch {
}
- launch,會在協(xié)程域中再開子協(xié)程。
runBlocking {
launch { }
}
- async方式,會在協(xié)程域中再開子協(xié)程。返回值是一個(gè)實(shí)現(xiàn)了Job接口的Dererred對象。
runBlocking {
async {
}
}
asnyc會返回一個(gè)Dererred對象。如果想要獲得async函數(shù)代碼塊的運(yùn)行結(jié)果,可以調(diào)用Dererred的await()方法。
runBlocking {
val deferred = async {
1+1
}
println(deferred.await())
}
await()方法會阻塞當(dāng)前協(xié)程,直到獲取到async函數(shù)的結(jié)果。
二、Dispatchers指定線程
- Dispatchers.Main:Android 中的主線程
- Dispatchers.IO:針對磁盤和網(wǎng)絡(luò) IO 進(jìn)行了優(yōu)化,適合 IO 密集型的任務(wù),比如:讀寫文件,操作數(shù)據(jù)庫以及網(wǎng)絡(luò)請求
- Dispatchers.Default:適合 CPU 密集型的任務(wù),比如計(jì)算
- Dispatchers.Unconfined:不推薦使用
runBlocking {
withContext(Dispatchers.Main){
}
withContext(Dispatchers.IO){
}
withContext(Dispatchers.Default){
}
}
三、suspend 關(guān)鍵字修飾的函數(shù)
表示該函數(shù)需要在協(xié)程中調(diào)用。
private suspend fun test(string:String) {
println(string)
}
private suspend fun test(string:String) = withContext(Dispatchers.IO){
}
private suspend fun test(string:String) :String = withContext(Dispatchers.IO){
"xxx"
}
協(xié)程代碼塊中代碼運(yùn)行到suspend函數(shù)時(shí),會暫時(shí)不再執(zhí)行剩余的協(xié)程代碼,而是先執(zhí)行完suspend函數(shù)再繼續(xù)往下執(zhí)行。
fun main(arg: Array<String>) {
CoroutineScope(Dispatchers.Default).launch {
println("1")
test() // 運(yùn)行到suspend函數(shù),會執(zhí)行完suspend函數(shù)之后再往下執(zhí)行
println("2")
}
Thread.sleep(6000)
println("end")
}
suspend fun test() {
delay(3000)
println("test")
}
運(yùn)行結(jié)果
1
test
2
end
四、子協(xié)程launch代碼塊
子協(xié)程launch代碼塊不會影響后面代碼的運(yùn)行(因?yàn)樽訁f(xié)程本來就是新的協(xié)程,和原來的代碼塊分開各跑各的)。
fun main(arg: Array<String>) {
CoroutineScope(Dispatchers.Default).launch {
launch { // 新的子協(xié)程,不影響后面代碼的運(yùn)行
delay(3000)
println("0")
}
test()
println("1")
}
Thread.sleep(6000)
println("end")
}
suspend fun test() {
delay(1000)
println("test")
}
運(yùn)行結(jié)果
test
1
0
end
六、coroutineScope函數(shù)和CoroutineScope函數(shù)的區(qū)別。
- coroutineScope函數(shù)是一個(gè)由suspend修飾的掛起函數(shù),需要在協(xié)程作用域中被調(diào)用。也可以在其它掛起函數(shù)中調(diào)用。coroutineScope{}中的代碼執(zhí)行完之前,一直阻塞外部協(xié)程(因?yàn)樗菕炱鸷瘮?shù))。
fun main() {
runBlocking { // runBlocking阻塞了外部線程
coroutineScope{
// coroutineScope阻塞了runBlocking協(xié)程
launch {
for (i in 1..10) {
println(i)
delay(1000)
}
}
}
println("runBlocking last line.")
}
println("main finished.")
}
運(yùn)行結(jié)果:
1
2
3
4
5
6
7
8
9
10
runBlocking last line.
main finished.
- CoroutineScope()是一個(gè)函數(shù),會返回一個(gè)CoroutineScope對象。之后調(diào)用它的launch函數(shù)就可以創(chuàng)建一個(gè)協(xié)程。不會阻塞外部線程、協(xié)程。
fun main() {
runBlocking {
CoroutineScope(Dispatchers.Default).launch{
for (i in 1..10) {
println(i)
delay(1000)
}
}
println("runBlocking last line.")
}
println("main finished.")
}
運(yùn)行結(jié)果:
既沒有阻塞外部線程也沒有阻塞外部協(xié)程。
runBlocking last line.
1
main finished.