Kotlin協(xié)程筆記

引入攜程所需庫

第一步:項目級build.gradle中

buildscript {
 ext.kotlin_coroutines = '1.3.1'
}

第二步:Module級別build.gradle中

dependencies {
 //                                       ?? 依賴協(xié)程核心庫
 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines"
 //                                       ?? 依賴當前平臺所對應(yīng)的平臺庫,如Android或js
 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines"
 //協(xié)程的聲明周期庫,該庫可以選加,是讓協(xié)程的生命周期和Activity的周期保持一致
 implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-alpha02'
}

注:核心庫和平臺庫版本需要保持一致

協(xié)程是什么

  • 協(xié)程:是一個線程框架,最核心的部分是【非阻塞式】和【掛起】;就是launch{協(xié)程部分}async{協(xié)程部分}

相關(guān)名詞

1、GloabScope:全局范圍
2、Coroutine:協(xié)程
3、suspend:掛起、暫停

  • a、代碼執(zhí)行到用suspend標識的函數(shù)時會掛起,且這種掛起是不會阻塞的,不會影響當前線程的執(zhí)行,而這種所謂的掛起,其實就是切一個線程,且在函數(shù)執(zhí)行完畢會自動將線程切回來的調(diào)度工作。
  • b、用suspend標識的函數(shù)只能運行在協(xié)程中;或者被另一個被suspend標識的函數(shù)調(diào)用,其實最終還是運行在一個協(xié)程中。
  • c、suspend本身是不能真正實現(xiàn)掛起的,他的作用主要是一個提醒,是創(chuàng)建者對使用者的提醒,該函數(shù)是一個耗時函數(shù),且是用掛起的方式在后臺運行,所以請在協(xié)程中調(diào)用我
  • d、suspend的意義:傳遞CoroutineContext

相關(guān)方法介紹

runBlocking :一般用于 單元測試中,是線程阻塞的

launch(Dispatchers.IO){}:可以用來切線程

coroutineScope.launch(Dispatchers.IO) {
    ...
    launch(Dispatchers.Main){
        ...
        launch(Dispatchers.IO) {
            ...
            launch(Dispatchers.Main) {
                ...
            }
        }
    }
}

withContext(){}:切換線程,當需要頻繁的進行線程切換時,因為可以自動切回原來的線程,所以相應(yīng)的代碼嵌套層次沒那么多,并在閉包內(nèi)的邏輯執(zhí)行結(jié)束后自動切回原來的線程,繼續(xù)執(zhí)行

coroutineScope.launch(Dispatchers.Main) {
    ...
    withContext(Dispatchers.IO) {
        ...
    }
    ...
    withContext(Dispatchers.IO) {
        ...
    }
    ...
}

Async{}:返回的協(xié)程實現(xiàn)了Deferred??梢允褂脀ait()方法

創(chuàng)建攜程的方法

方法一:使用runBlocking 頂層函數(shù),適用于單元測試的情況,是線程阻塞的,一般正常的業(yè)務(wù)開發(fā)不會使用

runBlocking{個人理解:此次相當于開啟一個線程,但是會阻塞當前線程,相當于一個耗時任務(wù)???
  getImage(imageId)
}

方法二:使用GlobalScope 單例對象,直接調(diào)用launch開啟協(xié)程,不會阻塞線程,但是實際開發(fā)中也一般不會使用,因為它的生命周期和APP的生命周期是一致的

GlobalScope.launch{
  getImage(imageId)
}

方法三:通過CoroutineContext創(chuàng)建一個CoroutineScope(接口)對象,需要一個類型為CoroutineContext的參數(shù)。開發(fā)中推薦這種方法,--coroutineContext?????

val coroutineScope = CoroutineScope(coroutineContext)
coroutineScope.launch{
  getImage(imageId)
}

方法四:主要用于在一個協(xié)程中開啟另一個協(xié)程,直接在普通代碼中無法使用

launch{
  
}

方法五:該方法與launch類似,也是在協(xié)程中使用

async{
  
}

async 和 launch對比

相同點:都可以用來啟動一個協(xié)程,返回的都是Coroutine

不同點:

  • async返回的Coroutine還實現(xiàn)了Deferred(意思是延遲,也就是結(jié)果稍后才能拿到。)接口。可以使用await暫停函數(shù)來返回result

  • launch可啟動新協(xié)程而不將結(jié)果返回給調(diào)用方

async使用場景:如現(xiàn)在需要展示公司LOGO和個人頭像,但是需要等待兩者都返回了,才可以去顯示,兩者同時進行,然后等較慢的執(zhí)行完畢就可以顯示了,所花費的時間就是兩個中較長的一個,而不是兩者之和

coroutineScope.launch(Dispatchers.Main) {
    //                      ??  async 函數(shù)啟動新的協(xié)程
    val avatar: Deferred = async { api.getAvatar(user) }    // 獲取用戶頭像
    val logo: Deferred = async { api.getCompanyLogo(user) } // 獲取用戶所在公司的 logo
    //            ??          ?? 獲取返回值
    show(avatar.await(), logo.await())                     // 更新 UI
}

掛起的本質(zhì)

什么是掛起:掛起就是稍后會自動切回來的操作

在協(xié)程中,我們掛起的對象既不是線程,也不是函數(shù),而是我們掛起的對象是協(xié)程,就是launch和async函數(shù)中的閉包的代碼塊,而launch和async或者其他函數(shù)創(chuàng)建的協(xié)程在執(zhí)行到某一個suspend函數(shù)的時候,這個函數(shù)就會被掛起,或者說從當前線程中脫離。

自定義suspend函數(shù)

  • 什么時候需要自定義suspend函數(shù)

    比如某個函數(shù)時比較函數(shù)的,可以將他協(xié)程suspend函數(shù),這就是原則
    耗時操作分為:I/O操作和CPU計算工作,比如文件讀寫,網(wǎng)絡(luò)交互,圖片的模糊處理。
    另一種耗時操作:如事情本身并不慢,但是因為某些原因需要等5s或者特定時間再執(zhí)行,這種也可以定義為suspend
    
  • 具體如何實現(xiàn)自定義

    1、給函數(shù)加上suspend關(guān)鍵字
    2、用withContext將函數(shù)內(nèi)容包?。ǚ奖銏?zhí)行完畢,自動切回原始線程)
    3、針對需要等待的耗時操作,我們可以直接使用另一個掛起函數(shù)delay()
    
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容