Android開發(fā)Kotlin語言協(xié)程的依賴及使用示例
一:協(xié)程的依賴
Kotlin 協(xié)程提供了一種全新處理并發(fā)的方式,你可以在 Android 平臺上使用它來簡化異步執(zhí)行的代碼。
如果是用于 Android 平臺的話,可以只引用以下的 coroutines-android,當中已經包含了 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.輕量:單個線程上可以運行多個協(xié)程,協(xié)程支持掛起,不會使正在運行的線程阻塞
2.內存泄漏更少:協(xié)程支持結構化并發(fā),從而避免了內存泄漏
3.Jetpact集成:Jetpack庫都包含提供全面協(xié)程的支持的擴展。
如: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é)程內部") Log.i("SecondActivity", "thread11=${Thread.currentThread().name}") } Log.i("SecondActivity", "協(xié)程下面") } 結果: 協(xié)程開始執(zhí)行 thread=main 協(xié)程下面 協(xié)程內部 thread11=DefaultDispatcher-worker-1
CoroutineContext
協(xié)程中使用 CoroutineScope(Dispatchers.IO)的Dispatchers.IO 是CoroutineContext的子類實現(xiàn)
CoroutineContext。即協(xié)程上下文,包含多種類型的配置參數(shù)。Dispatchers.IO 就是 CoroutineContext 這個抽象概念的一種實現(xiàn),用于指定協(xié)程的運行載體,即用于指定協(xié)程要運行在哪類線程上
@Suppress("FunctionName") public fun CoroutineScope(context: CoroutineContext): CoroutineScope = ContextScope(if (context[Job] != null) context else context + Job())
Kotlin 協(xié)程庫提供了四個 Dispatcher 用于指定在哪一類線程中執(zhí)行協(xié)程:
- Dispatchers.Default。默認調度器,適合用于執(zhí)行占用大量 CPU 資源的任務。例如:對列表排序和解析 JSON
- Dispatchers.IO。適合用于執(zhí)行磁盤或網絡 I/O 的任務。例如:使用 Room 組件、讀寫磁盤文件,執(zhí)行網絡請求
- Dispatchers.Unconfined。對執(zhí)行協(xié)程的線程不做限制,可以直接在當前調度器所在線程上執(zhí)行
- Dispatchers.Main。使用此調度程序可用于在 Android 主線程上運行協(xié)程,只能用于與界面交互和執(zhí)行快速工作,例如:更新 UI、調用 LiveData.setValue
CoroutineScope
CoroutineScope 即 協(xié)程作用域,用于對協(xié)程進行追蹤。如果我們啟動了多個協(xié)程但是沒有一個可以對其進行統(tǒng)一管理的途徑的話,就會導致我們的代碼臃腫雜亂,甚至發(fā)生內存泄露或者任務泄露。為了確保所有的協(xié)程都會被追蹤,Kotlin 不允許在沒有 CoroutineScope 的情況下啟動協(xié)程。CoroutineScope 可被看作是一個具有超能力的 ExecutorService 的輕量級版本。它能啟動協(xié)程,同時這個協(xié)程還具備上文所說的 suspend 和 resume 的優(yōu)勢
suspend
suspend 是協(xié)程中很重的關鍵字,它用來修飾函數(shù),表示此函數(shù)是一個會掛起的函數(shù),并且 掛起函數(shù)只有在協(xié)程中使用或者被另一個掛起函數(shù)調用,可以暫停和進行恢復,什么情況下需要用到掛起函數(shù)
- 線程切換,掛起本身是線程切換不同的協(xié)程去工作,所以當需要進行線程切換時可以使用掛起函數(shù)
- 延遲,暫停往往代表在等待一些結果,當我們在等待一些返回結果時,協(xié)程可以通過掛起的方式等待,而不是阻塞線程
suspend只是對函數(shù)的一個標識別,它不像inline,refied等關鍵字一樣會對代碼造成影響,而是提醒使用者這是一個掛起函數(shù),具體的掛起業(yè)務還是需要函數(shù)內部自己實現(xiàn)
withContext
withContext是一個掛起函數(shù),表明它只能在協(xié)程或者其他suspend函數(shù)調用
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é)程內部") 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
- 不會阻塞直到結果返回
- 不會阻塞線程
- 并行執(zhí)行
withContext:
- 會阻塞當前協(xié)程直到函數(shù)返回
- 從指定的Dispatcher執(zhí)行函數(shù)
- 當執(zhí)行函數(shù)的時候不會阻塞線程
- 串行執(zhí)行
async
- 當使用awiat函數(shù)時,會阻塞直到結果返回
- 如果不使用await,其效果與launch一樣
- 適用于多個并行任務但需要等待結果返回情形
- 并行執(zhí)行
什么是 Job ?
Job 翻譯作任務,Job 賦予協(xié)程可取消,賦予協(xié)程以生命周期,賦予協(xié)程以結構化并發(fā)的能力。其中平常使用中最為重要的是可取消、結構化并發(fā)的特點。尤其 在日常 Android 開發(fā)過程中,協(xié)程配合 Lifecycle 可以做到自動取消。
Job 的生命周期
Job 的生命周期分為 6 種狀態(tài),分為 New、Active、Completing、Cancelling、Cancelled、Completed,通常外界會持有 Job 接口會作為引用被協(xié)程調用者所持有,Job 接口提供 isActive、isCompleted、isCancelled 3 個變量使外界可以感知 Job 內部的狀態(tài),這3個變量和 Job 生命周期的6種狀態(tài)的對應關系如下圖所示
栗子: 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é)程可以想象成是一個工作任務,啟動一個協(xié)程就是啟動一個工作任務,來看看 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é)程已經啟動、沒有完成、沒有被取消 public val isActive: Boolean //是否完成狀態(tài) public val isCompleted: Boolean //是否被取消狀態(tài) public val isCancelled: Boolean //啟動協(xié)程,開始調度。如果已經啟動了,則返回false。與線程的Thread.start()挺類似 public fun start(): Boolean //掛起當前正在運行的協(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里,可以用“?”表示可以為空,也可以用“!!”表示不可以為空。
給變量加上?標識,會通告所有使用該變量的地方,必須給出為空的補救措施。
var info: String? = null println(info?.length) //第一種補救:如果info為null,就不執(zhí)行后面的.length代碼 println(info!!.length) //第二種補救:這里如果為null,我自己負責info,會報出空指針,這種處理需慎用 if (info != null) { //第三種補救措施,如下這種同java寫法 println(info.length) } println(info?.length ?: "空數(shù)據(jù)") //第四種補救措施,如果真的為null,則改為返回"空數(shù)據(jù)"
以上就是Android開發(fā)Kotlin語言協(xié)程的依賴及使用示例的詳細內容,更多關于Android Kotlin協(xié)程依賴的資料請關注腳本之家其它相關文章!
相關文章
android中ListView數(shù)據(jù)刷新時的同步方法
這篇文章主要介紹了android中ListView數(shù)據(jù)刷新時的同步方法,涉及Android刷新listview實現(xiàn)數(shù)據(jù)同步的技巧,需要的朋友可以參考下2015-05-05Android動畫效果之自定義ViewGroup添加布局動畫(五)
這篇文章主要介紹了Android動畫效果之自定義ViewGroup添加布局動畫,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-08-08Android Material Design 陰影實現(xiàn)示例
這篇文章主要介紹了Android Material Design 陰影實現(xiàn)示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-04-04React Native 實現(xiàn)熱更新并自動簽名打包功能
這篇文章主要介紹了React Native 實現(xiàn)熱更新并自動簽名打包,本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-04-04