Android開發(fā)Kotlin語言協(xié)程的依賴及使用示例
一:協(xié)程的依賴
Kotlin 協(xié)程提供了一種全新處理并發(fā)的方式,你可以在 Android 平臺上使用它來簡化異步執(zhí)行的代碼。
如果是用于 Android 平臺的話,可以只引用以下的 coroutines-android,當(dāng)中已經(jīng)包含了 coroutines-core
//協(xié)程依賴 implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
協(xié)程優(yōu)勢:
1.輕量:單個線程上可以運(yùn)行多個協(xié)程,協(xié)程支持掛起,不會使正在運(yùn)行的線程阻塞
2.內(nèi)存泄漏更少:協(xié)程支持結(jié)構(gòu)化并發(fā),從而避免了內(nèi)存泄漏
3.Jetpact集成:Jetpack庫都包含提供全面協(xié)程的支持的擴(kuò)展。
如:ViewModelSocpe,LifecycleScope,LiveData
二:協(xié)程使用
1.簡單使用
//開啟協(xié)程
fun runCoroutine() {
Log.i("SecondActivity", "協(xié)程開始執(zhí)行")
Log.i("SecondActivity", "thread=${Thread.currentThread().name}")
CoroutineScope(Dispatchers.IO).launch {
delay(2000)
Log.i("SecondActivity", "協(xié)程內(nèi)部")
Log.i("SecondActivity", "thread11=${Thread.currentThread().name}")
}
Log.i("SecondActivity", "協(xié)程下面")
}
結(jié)果:
協(xié)程開始執(zhí)行
thread=main
協(xié)程下面
協(xié)程內(nèi)部
thread11=DefaultDispatcher-worker-1CoroutineContext
協(xié)程中使用 CoroutineScope(Dispatchers.IO)的Dispatchers.IO 是CoroutineContext的子類實現(xiàn)
CoroutineContext。即協(xié)程上下文,包含多種類型的配置參數(shù)。Dispatchers.IO 就是 CoroutineContext 這個抽象概念的一種實現(xiàn),用于指定協(xié)程的運(yùn)行載體,即用于指定協(xié)程要運(yùn)行在哪類線程上
@Suppress("FunctionName")
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
ContextScope(if (context[Job] != null) context else context + Job())
Kotlin 協(xié)程庫提供了四個 Dispatcher 用于指定在哪一類線程中執(zhí)行協(xié)程:
- Dispatchers.Default。默認(rèn)調(diào)度器,適合用于執(zhí)行占用大量 CPU 資源的任務(wù)。例如:對列表排序和解析 JSON
- Dispatchers.IO。適合用于執(zhí)行磁盤或網(wǎng)絡(luò) I/O 的任務(wù)。例如:使用 Room 組件、讀寫磁盤文件,執(zhí)行網(wǎng)絡(luò)請求
- Dispatchers.Unconfined。對執(zhí)行協(xié)程的線程不做限制,可以直接在當(dāng)前調(diào)度器所在線程上執(zhí)行
- Dispatchers.Main。使用此調(diào)度程序可用于在 Android 主線程上運(yùn)行協(xié)程,只能用于與界面交互和執(zhí)行快速工作,例如:更新 UI、調(diào)用 LiveData.setValue
CoroutineScope
CoroutineScope 即 協(xié)程作用域,用于對協(xié)程進(jìn)行追蹤。如果我們啟動了多個協(xié)程但是沒有一個可以對其進(jìn)行統(tǒng)一管理的途徑的話,就會導(dǎo)致我們的代碼臃腫雜亂,甚至發(fā)生內(nèi)存泄露或者任務(wù)泄露。為了確保所有的協(xié)程都會被追蹤,Kotlin 不允許在沒有 CoroutineScope 的情況下啟動協(xié)程。CoroutineScope 可被看作是一個具有超能力的 ExecutorService 的輕量級版本。它能啟動協(xié)程,同時這個協(xié)程還具備上文所說的 suspend 和 resume 的優(yōu)勢
suspend
suspend 是協(xié)程中很重的關(guān)鍵字,它用來修飾函數(shù),表示此函數(shù)是一個會掛起的函數(shù),并且 掛起函數(shù)只有在協(xié)程中使用或者被另一個掛起函數(shù)調(diào)用,可以暫停和進(jìn)行恢復(fù),什么情況下需要用到掛起函數(shù)
- 線程切換,掛起本身是線程切換不同的協(xié)程去工作,所以當(dāng)需要進(jìn)行線程切換時可以使用掛起函數(shù)
- 延遲,暫停往往代表在等待一些結(jié)果,當(dāng)我們在等待一些返回結(jié)果時,協(xié)程可以通過掛起的方式等待,而不是阻塞線程
suspend只是對函數(shù)的一個標(biāo)識別,它不像inline,refied等關(guān)鍵字一樣會對代碼造成影響,而是提醒使用者這是一個掛起函數(shù),具體的掛起業(yè)務(wù)還是需要函數(shù)內(nèi)部自己實現(xiàn)
withContext
withContext是一個掛起函數(shù),表明它只能在協(xié)程或者其他suspend函數(shù)調(diào)用
public suspend fun <T> withContext(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T {
}launch
lauch是最常見的啟動一個協(xié)程的方法,可以通過GlobalScope.launch開啟一個全局生命周期的協(xié)程,也可以通過CoroutineScope(CoroutineContext).launch 來開啟一個在指定的 CoroutneContext 范圍的協(xié)程。也可以記錄這個Job并通過Job.cancel()隨時取消
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}val apiService by lazy { RetrofitClient.instance.create() }
//開啟協(xié)程
fun runCoroutine(name: String, password: String, resultListener: (String, String) -> Unit) {
Log.i("SecondActivity", "協(xié)程開始執(zhí)行")
Log.i("SecondActivity", "thread=${Thread.currentThread().name}")
CoroutineScope(Dispatchers.IO).launch {
Log.i("SecondActivity", "協(xié)程內(nèi)部")
Log.i("SecondActivity", "thread11=${Thread.currentThread().name}")
val request = HttpAccountLoginRequest(name, password, null)
val block :suspend CoroutineScope.()->BaseResult<HttpAccountLoginResponse> ={
apiService.requestAccountLogin(request,"android","3.5.4")
}
var result:BaseResult<HttpAccountLoginResponse> =block()
if (result.code=="200"&&result.datas!=null){
withContext(Dispatchers.Main){
}
}
}
Log.i("SecondActivity", "協(xié)程下面")
}launch
- 不會阻塞直到結(jié)果返回
- 不會阻塞線程
- 并行執(zhí)行
withContext:
- 會阻塞當(dāng)前協(xié)程直到函數(shù)返回
- 從指定的Dispatcher執(zhí)行函數(shù)
- 當(dāng)執(zhí)行函數(shù)的時候不會阻塞線程
- 串行執(zhí)行
async
- 當(dāng)使用awiat函數(shù)時,會阻塞直到結(jié)果返回
- 如果不使用await,其效果與launch一樣
- 適用于多個并行任務(wù)但需要等待結(jié)果返回情形
- 并行執(zhí)行
什么是 Job ?
Job 翻譯作任務(wù),Job 賦予協(xié)程可取消,賦予協(xié)程以生命周期,賦予協(xié)程以結(jié)構(gòu)化并發(fā)的能力。其中平常使用中最為重要的是可取消、結(jié)構(gòu)化并發(fā)的特點。尤其 在日常 Android 開發(fā)過程中,協(xié)程配合 Lifecycle 可以做到自動取消。
Job 的生命周期
Job 的生命周期分為 6 種狀態(tài),分為 New、Active、Completing、Cancelling、Cancelled、Completed,通常外界會持有 Job 接口會作為引用被協(xié)程調(diào)用者所持有,Job 接口提供 isActive、isCompleted、isCancelled 3 個變量使外界可以感知 Job 內(nèi)部的狀態(tài),這3個變量和 Job 生命周期的6種狀態(tài)的對應(yīng)關(guān)系如下圖所示

栗子:
CoroutineScope(Dispatchers.IO).async {
}
源碼:
public fun <T> CoroutineScope.async(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> T
): Deferred<T> {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyDeferredCoroutine(newContext, block) else
DeferredCoroutine<T>(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}栗子:
CoroutineScope(Dispatchers.IO).launch {
}
源碼:
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job {
val newContext = newCoroutineContext(context)
val coroutine = if (start.isLazy)
LazyStandaloneCoroutine(newContext, block) else
StandaloneCoroutine(newContext, active = true)
coroutine.start(start, coroutine, block)
return coroutine
}一種是通過 launch 啟動,一種是通過 async 啟動,前者會返回一個 Job 類型的對象,后者會返回一個 Deferred 類型的對象
Job的接口定義
Job 顧名思義就是“工作”的意思,每個協(xié)程可以想象成是一個工作任務(wù),啟動一個協(xié)程就是啟動一個工作任務(wù),來看看 Job 接口的主要定義:
//Job 也是繼承自 Element,所以它本身也是一個協(xié)程上下文 context
public interface Job : CoroutineContext.Element {
//Key對象,如果你看到 context[Job] 的寫法, 就知道其實指的是這里的這個伴生對象 Key
public companion object Key : CoroutineContext.Key<Job> {
init {
CoroutineExceptionHandler
}
}
//是否活動狀態(tài),必須滿足幾個條件:該協(xié)程已經(jīng)啟動、沒有完成、沒有被取消
public val isActive: Boolean
//是否完成狀態(tài)
public val isCompleted: Boolean
//是否被取消狀態(tài)
public val isCancelled: Boolean
//啟動協(xié)程,開始調(diào)度。如果已經(jīng)啟動了,則返回false。與線程的Thread.start()挺類似
public fun start(): Boolean
//掛起當(dāng)前正在運(yùn)行的協(xié)程,等待該 Job 執(zhí)行完成。與線程的Thread.join()挺類似
public suspend fun join()
//取消該 Job
public fun cancel(cause: CancellationException? = null)
//該 Job 的子 Job
public val children: Sequence<Job>
}小知識:
Kotlin空指針檢查
在Kotlin里,可以用“?”表示可以為空,也可以用“!!”表示不可以為空。
給變量加上?標(biāo)識,會通告所有使用該變量的地方,必須給出為空的補(bǔ)救措施。
var info: String? = null
println(info?.length) //第一種補(bǔ)救:如果info為null,就不執(zhí)行后面的.length代碼
println(info!!.length) //第二種補(bǔ)救:這里如果為null,我自己負(fù)責(zé)info,會報出空指針,這種處理需慎用
if (info != null) { //第三種補(bǔ)救措施,如下這種同java寫法
println(info.length)
}
println(info?.length ?: "空數(shù)據(jù)") //第四種補(bǔ)救措施,如果真的為null,則改為返回"空數(shù)據(jù)"以上就是Android開發(fā)Kotlin語言協(xié)程的依賴及使用示例的詳細(xì)內(nèi)容,更多關(guān)于Android Kotlin協(xié)程依賴的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
android POST數(shù)據(jù)遇到的UTF-8編碼(亂碼)問題解決辦法
這篇文章主要介紹了android POST數(shù)據(jù)遇到的UTF-8編碼(亂碼)問題解決辦法,需要的朋友可以參考下2014-04-04
Android ViewPager實現(xiàn)無限循環(huán)輪播廣告位Banner效果
這篇文章主要為大家詳細(xì)介紹了Android ViewPager實現(xiàn)無限循環(huán)輪播廣告位Banner效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-07-07
Android開發(fā)技巧之像QQ一樣輸入文字和表情圖像
QQ聊天輸入框,在輸入框中可以同時輸入文字和表情圖像。實際上,這種效果在Android SDK中只需要幾行代碼就可以實現(xiàn),本文將會介紹如何實現(xiàn)像QQ一樣輸入表情圖像2013-01-01
Android TextView實現(xiàn)點擊顯示全文與隱藏功能(附源碼)
TextView用法很多,用到的地方更是普遍,所以學(xué)好TextView的使用很重要很重要很重要。下面這篇文章主要介紹了Android中TextView實現(xiàn)顯示全文與隱藏功能的相關(guān)資料,文中給出了詳細(xì)的示例代碼和源碼下載,需要的朋友可以參考下。2017-03-03
Android設(shè)置透明狀態(tài)欄和透明導(dǎo)航欄
本文主要介紹了Android設(shè)置透明狀態(tài)欄和透明導(dǎo)航欄的方法。具有很好的參考價值。下面跟著小編一起來看下吧2017-03-03
關(guān)于Android內(nèi)存緩存LruCache的使用及其源碼解析
LruCache作為內(nèi)存緩存,使用強(qiáng)引用方式緩存有限個數(shù)據(jù),當(dāng)緩存的某個數(shù)據(jù)被訪問時,它就會被移動到隊列的頭部,本文詳細(xì)介紹了關(guān)于Android內(nèi)存緩存LruCache的使用及其源碼解析,需要的朋友可以參考下2023-05-05
Android自定義ProgressBar實現(xiàn)漂亮的進(jìn)度提示框
這篇文章主要為大家詳細(xì)介紹了Android自定義ProgressBar實現(xiàn)漂亮的進(jìn)度提示框,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-06-06
Android實現(xiàn)帶有刪除按鈕的EditText示例代碼
本文給大家介紹一個很實用的小控件,就是在Android系統(tǒng)的輸入框右邊加入一個小圖標(biāo),點擊小圖標(biāo)可以清除輸入框里面的內(nèi)容,IOS上面直接設(shè)置某個屬性就可以實現(xiàn)這一功能,但是Android原生EditText不具備此功能,所以要想實現(xiàn)這一功能我們需要重寫EditText。下面來看看吧。2016-12-12

