Android開(kāi)發(fā)Kotlin語(yǔ)言協(xié)程的依賴(lài)及使用示例
一:協(xié)程的依賴(lài)
Kotlin 協(xié)程提供了一種全新處理并發(fā)的方式,你可以在 Android 平臺(tái)上使用它來(lái)簡(jiǎn)化異步執(zhí)行的代碼。
如果是用于 Android 平臺(tái)的話(huà),可以只引用以下的 coroutines-android,當(dāng)中已經(jīng)包含了 coroutines-core
//協(xié)程依賴(lài) implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4"
協(xié)程優(yōu)勢(shì):
1.輕量:?jiǎn)蝹€(gè)線(xiàn)程上可以運(yùn)行多個(gè)協(xié)程,協(xié)程支持掛起,不會(huì)使正在運(yùn)行的線(xiàn)程阻塞
2.內(nèi)存泄漏更少:協(xié)程支持結(jié)構(gòu)化并發(fā),從而避免了內(nèi)存泄漏
3.Jetpact集成:Jetpack庫(kù)都包含提供全面協(xié)程的支持的擴(kuò)展。
如:ViewModelSocpe,LifecycleScope,LiveData
二:協(xié)程使用
1.簡(jiǎn)單使用
//開(kāi)啟協(xié)程
fun runCoroutine() {
Log.i("SecondActivity", "協(xié)程開(kāi)始執(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é)程開(kāi)始執(zhí)行
thread=main
協(xié)程下面
協(xié)程內(nèi)部
thread11=DefaultDispatcher-worker-1CoroutineContext
協(xié)程中使用 CoroutineScope(Dispatchers.IO)的Dispatchers.IO 是CoroutineContext的子類(lèi)實(shí)現(xiàn)
CoroutineContext。即協(xié)程上下文,包含多種類(lèi)型的配置參數(shù)。Dispatchers.IO 就是 CoroutineContext 這個(gè)抽象概念的一種實(shí)現(xiàn),用于指定協(xié)程的運(yùn)行載體,即用于指定協(xié)程要運(yùn)行在哪類(lèi)線(xiàn)程上
@Suppress("FunctionName")
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
ContextScope(if (context[Job] != null) context else context + Job())
Kotlin 協(xié)程庫(kù)提供了四個(gè) Dispatcher 用于指定在哪一類(lèi)線(xiàn)程中執(zhí)行協(xié)程:
- Dispatchers.Default。默認(rèn)調(diào)度器,適合用于執(zhí)行占用大量 CPU 資源的任務(wù)。例如:對(duì)列表排序和解析 JSON
- Dispatchers.IO。適合用于執(zhí)行磁盤(pán)或網(wǎng)絡(luò) I/O 的任務(wù)。例如:使用 Room 組件、讀寫(xiě)磁盤(pán)文件,執(zhí)行網(wǎng)絡(luò)請(qǐng)求
- Dispatchers.Unconfined。對(duì)執(zhí)行協(xié)程的線(xiàn)程不做限制,可以直接在當(dāng)前調(diào)度器所在線(xiàn)程上執(zhí)行
- Dispatchers.Main。使用此調(diào)度程序可用于在 Android 主線(xiàn)程上運(yùn)行協(xié)程,只能用于與界面交互和執(zhí)行快速工作,例如:更新 UI、調(diào)用 LiveData.setValue
CoroutineScope
CoroutineScope 即 協(xié)程作用域,用于對(duì)協(xié)程進(jìn)行追蹤。如果我們啟動(dòng)了多個(gè)協(xié)程但是沒(méi)有一個(gè)可以對(duì)其進(jìn)行統(tǒng)一管理的途徑的話(huà),就會(huì)導(dǎo)致我們的代碼臃腫雜亂,甚至發(fā)生內(nèi)存泄露或者任務(wù)泄露。為了確保所有的協(xié)程都會(huì)被追蹤,Kotlin 不允許在沒(méi)有 CoroutineScope 的情況下啟動(dòng)協(xié)程。CoroutineScope 可被看作是一個(gè)具有超能力的 ExecutorService 的輕量級(jí)版本。它能啟動(dòng)協(xié)程,同時(shí)這個(gè)協(xié)程還具備上文所說(shuō)的 suspend 和 resume 的優(yōu)勢(shì)
suspend
suspend 是協(xié)程中很重的關(guān)鍵字,它用來(lái)修飾函數(shù),表示此函數(shù)是一個(gè)會(huì)掛起的函數(shù),并且 掛起函數(shù)只有在協(xié)程中使用或者被另一個(gè)掛起函數(shù)調(diào)用,可以暫停和進(jìn)行恢復(fù),什么情況下需要用到掛起函數(shù)
- 線(xiàn)程切換,掛起本身是線(xiàn)程切換不同的協(xié)程去工作,所以當(dāng)需要進(jìn)行線(xiàn)程切換時(shí)可以使用掛起函數(shù)
- 延遲,暫停往往代表在等待一些結(jié)果,當(dāng)我們?cè)诘却恍┓祷亟Y(jié)果時(shí),協(xié)程可以通過(guò)掛起的方式等待,而不是阻塞線(xiàn)程
suspend只是對(duì)函數(shù)的一個(gè)標(biāo)識(shí)別,它不像inline,refied等關(guān)鍵字一樣會(huì)對(duì)代碼造成影響,而是提醒使用者這是一個(gè)掛起函數(shù),具體的掛起業(yè)務(wù)還是需要函數(shù)內(nèi)部自己實(shí)現(xiàn)
withContext
withContext是一個(gè)掛起函數(shù),表明它只能在協(xié)程或者其他suspend函數(shù)調(diào)用
public suspend fun <T> withContext(
context: CoroutineContext,
block: suspend CoroutineScope.() -> T
): T {
}launch
lauch是最常見(jiàn)的啟動(dòng)一個(gè)協(xié)程的方法,可以通過(guò)GlobalScope.launch開(kāi)啟一個(gè)全局生命周期的協(xié)程,也可以通過(guò)CoroutineScope(CoroutineContext).launch 來(lái)開(kāi)啟一個(gè)在指定的 CoroutneContext 范圍的協(xié)程。也可以記錄這個(gè)Job并通過(guò)Job.cancel()隨時(shí)取消
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() }
//開(kāi)啟協(xié)程
fun runCoroutine(name: String, password: String, resultListener: (String, String) -> Unit) {
Log.i("SecondActivity", "協(xié)程開(kāi)始執(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
- 不會(huì)阻塞直到結(jié)果返回
- 不會(huì)阻塞線(xiàn)程
- 并行執(zhí)行
withContext:
- 會(huì)阻塞當(dāng)前協(xié)程直到函數(shù)返回
- 從指定的Dispatcher執(zhí)行函數(shù)
- 當(dāng)執(zhí)行函數(shù)的時(shí)候不會(huì)阻塞線(xiàn)程
- 串行執(zhí)行
async
- 當(dāng)使用awiat函數(shù)時(shí),會(huì)阻塞直到結(jié)果返回
- 如果不使用await,其效果與launch一樣
- 適用于多個(gè)并行任務(wù)但需要等待結(jié)果返回情形
- 并行執(zhí)行
什么是 Job ?
Job 翻譯作任務(wù),Job 賦予協(xié)程可取消,賦予協(xié)程以生命周期,賦予協(xié)程以結(jié)構(gòu)化并發(fā)的能力。其中平常使用中最為重要的是可取消、結(jié)構(gòu)化并發(fā)的特點(diǎn)。尤其 在日常 Android 開(kāi)發(fā)過(guò)程中,協(xié)程配合 Lifecycle 可以做到自動(dòng)取消。
Job 的生命周期
Job 的生命周期分為 6 種狀態(tài),分為 New、Active、Completing、Cancelling、Cancelled、Completed,通常外界會(huì)持有 Job 接口會(huì)作為引用被協(xié)程調(diào)用者所持有,Job 接口提供 isActive、isCompleted、isCancelled 3 個(gè)變量使外界可以感知 Job 內(nèi)部的狀態(tài),這3個(gè)變量和 Job 生命周期的6種狀態(tài)的對(duì)應(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
}一種是通過(guò) launch 啟動(dòng),一種是通過(guò) async 啟動(dòng),前者會(huì)返回一個(gè) Job 類(lèi)型的對(duì)象,后者會(huì)返回一個(gè) Deferred 類(lèi)型的對(duì)象
Job的接口定義
Job 顧名思義就是“工作”的意思,每個(gè)協(xié)程可以想象成是一個(gè)工作任務(wù),啟動(dòng)一個(gè)協(xié)程就是啟動(dòng)一個(gè)工作任務(wù),來(lái)看看 Job 接口的主要定義:
//Job 也是繼承自 Element,所以它本身也是一個(gè)協(xié)程上下文 context
public interface Job : CoroutineContext.Element {
//Key對(duì)象,如果你看到 context[Job] 的寫(xiě)法, 就知道其實(shí)指的是這里的這個(gè)伴生對(duì)象 Key
public companion object Key : CoroutineContext.Key<Job> {
init {
CoroutineExceptionHandler
}
}
//是否活動(dòng)狀態(tài),必須滿(mǎn)足幾個(gè)條件:該協(xié)程已經(jīng)啟動(dòng)、沒(méi)有完成、沒(méi)有被取消
public val isActive: Boolean
//是否完成狀態(tài)
public val isCompleted: Boolean
//是否被取消狀態(tài)
public val isCancelled: Boolean
//啟動(dòng)協(xié)程,開(kāi)始調(diào)度。如果已經(jīng)啟動(dòng)了,則返回false。與線(xiàn)程的Thread.start()挺類(lèi)似
public fun start(): Boolean
//掛起當(dāng)前正在運(yùn)行的協(xié)程,等待該 Job 執(zhí)行完成。與線(xiàn)程的Thread.join()挺類(lèi)似
public suspend fun join()
//取消該 Job
public fun cancel(cause: CancellationException? = null)
//該 Job 的子 Job
public val children: Sequence<Job>
}小知識(shí):
Kotlin空指針檢查
在Kotlin里,可以用“?”表示可以為空,也可以用“!!”表示不可以為空。
給變量加上?標(biāo)識(shí),會(huì)通告所有使用該變量的地方,必須給出為空的補(bǔ)救措施。
var info: String? = null
println(info?.length) //第一種補(bǔ)救:如果info為null,就不執(zhí)行后面的.length代碼
println(info!!.length) //第二種補(bǔ)救:這里如果為null,我自己負(fù)責(zé)info,會(huì)報(bào)出空指針,這種處理需慎用
if (info != null) { //第三種補(bǔ)救措施,如下這種同java寫(xiě)法
println(info.length)
}
println(info?.length ?: "空數(shù)據(jù)") //第四種補(bǔ)救措施,如果真的為null,則改為返回"空數(shù)據(jù)"以上就是Android開(kāi)發(fā)Kotlin語(yǔ)言協(xié)程的依賴(lài)及使用示例的詳細(xì)內(nèi)容,更多關(guān)于Android Kotlin協(xié)程依賴(lài)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Android自動(dòng)測(cè)試工具M(jìn)onkey
Monkey是Android中的一個(gè)命令行工具,可以運(yùn)行在模擬器里或?qū)嶋H設(shè)備中。它向系統(tǒng)發(fā)送偽隨機(jī)的用戶(hù)事件流(如按鍵輸入、觸摸屏輸入、手勢(shì)輸入等),實(shí)現(xiàn)對(duì)正在開(kāi)發(fā)的應(yīng)用程序進(jìn)行壓力測(cè)試。Monkey測(cè)試是一種為了測(cè)試軟件的穩(wěn)定性、健壯性的快速有效的方法2016-01-01
android中ListView數(shù)據(jù)刷新時(shí)的同步方法
這篇文章主要介紹了android中ListView數(shù)據(jù)刷新時(shí)的同步方法,涉及Android刷新listview實(shí)現(xiàn)數(shù)據(jù)同步的技巧,需要的朋友可以參考下2015-05-05
Android動(dòng)畫(huà)效果之自定義ViewGroup添加布局動(dòng)畫(huà)(五)
這篇文章主要介紹了Android動(dòng)畫(huà)效果之自定義ViewGroup添加布局動(dòng)畫(huà),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-08-08
Android Material Design 陰影實(shí)現(xiàn)示例
這篇文章主要介紹了Android Material Design 陰影實(shí)現(xiàn)示例,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-04-04
Android studio 廣播的簡(jiǎn)單使用代碼詳解
這篇文章主要介紹了Android studio 廣播的簡(jiǎn)單使用,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-04-04
使用Android自定義控件實(shí)現(xiàn)滑動(dòng)解鎖九宮格
最近由于Android項(xiàng)目需要,要求做一個(gè)類(lèi)似于支付寶的九宮格解鎖組件,下面小編給大家分享了具體實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-10-10
React Native 實(shí)現(xiàn)熱更新并自動(dòng)簽名打包功能
這篇文章主要介紹了React Native 實(shí)現(xiàn)熱更新并自動(dòng)簽名打包,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04

