欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Kotlin Coroutines執(zhí)行異步加載示例詳解

 更新時間:2018年01月30日 08:46:26   作者:尺錘  
這篇文章主要給大家介紹了關(guān)于Kotlin Coroutines執(zhí)行異步加載的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧。

前言

Kotlin Coroutines是Kotlin推出的新的異步API。并不是解決所有問題的最優(yōu)方案,但是希望在許多情況下它會使事情變得更容易一些。這里只簡單的展示一下這個庫在安卓中的具體使用方案。下面話不多說了,來一起看看詳細的介紹吧。

引入Coroutines

//在application的build.gradle文件中的android節(jié)點添加如下的代碼
kotlin {
 experimental {
  coroutines 'enable'
 }
}

//添加下面兩行到依賴中
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:0.20"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:0.20"

第一個Coroutines示例

通常我們加載一張圖片到ImageView中,異步的加載任務(wù)如下所示:

fun loadBitmapFromMediaStore(imageId: Int, 
        imagesBaseUri: Uri): Bitmap {
 val uri = Uri.withAppendedPath(imagesBaseUri, imageId.toString())
 return MediaStore.Images.Media.getBitmap(contentResolver, uri)
}

這個方法必須在后臺線程中執(zhí)行,因為他屬于一個IO操作,這意味著我們有很多解決方案可以啟動后臺任務(wù),一旦該方法返回一個bitmap,我們需要立即顯示在Imageview中。

imageView.setImageBitmap(bitmap)

這行代碼必須在主線程執(zhí)行,否則會crash。

以上三行代碼如果寫到一起將會導(dǎo)致程序卡死或者是閃退,這都取決于合理的選擇線程。接下來我們看一下使用kotlin的Coroutines是如何解決這個問題的:

val job = launch(Background) {
 val uri = Uri.withAppendedPath(imagesBaseUri, imageId.toString())
 val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, 
 launch(UI) {
 imageView.setImageBitmap(bitmap)
 }
}

這里最重要的是launch()和參數(shù)Background和UI,launch()表示創(chuàng)建和啟動一個Coroutine,Background參數(shù)CoroutineContext用來保證在后臺線程執(zhí)行,從而保證應(yīng)用程序不會卡死或者閃退,你可以聲明一個如下面所示的CoroutineContext。

internal val Background = newFixedThreadPoolContext(2, "bg")

這將創(chuàng)建一個新的上下文,并在執(zhí)行他的任務(wù)的時候使用兩個常規(guī)的線程。

接下來說launch(UI),這將觸發(fā)另一個coroutine,將執(zhí)行在Android
的主線程。

可取消

接下來的挑戰(zhàn)是處理跟Activity聲明周期相關(guān)的東西,當(dāng)你在加載一個任務(wù),還沒有執(zhí)行完的時候離開了該Activity,以至于他在調(diào)用imageView.setImageBitmap(bitmap)就會引起crash,所以我們在離開該activity之前就需要取消該任務(wù),這里就用到了launch()方法的返回值job,當(dāng)activity調(diào)用onStop方法時,我們需要使用job來取消任務(wù)

job.cancel()

這就像你使用Rxjava時調(diào)用dispose和使用AsyncTask時調(diào)用cancel函數(shù)是一個道理。

LifecycleObserver

Android Architecture Components 給安卓開發(fā)者提供了特別多強大的庫,其中之一就是Lifecycle API.給我們提供了一個簡便的方法用來實時的監(jiān)聽activity和fragment的生命周期,我們定義一下代碼與coroutines一起使用。

class CoroutineLifecycleListener(val deferred: Deferred<*>) : LifecycleObserver {
 @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
 fun cancelCoroutine() {
 if (!deferred.isCancelled) {
  deferred.cancel()
 }
 }
}

我們創(chuàng)建一個LifecycleOwner的擴展函數(shù):

fun <T> LifecycleOwner.load(loader: () -> T): Deferred<T> {
 val deferred = async(context = Background, 
      start = CoroutineStart.LAZY) {
 loader()
 }
 lifecycle.addObserver(CoroutineLifecycleListener(deferred))
 return deferred
}

這個方法中有太多新的東西,接下來一一解釋:

現(xiàn)在我們可以在一個activity或fragment中調(diào)用load() ,并從該函數(shù)中訪問生命周期成員,并將我們的CoroutineLifecycleListener添加為觀察者。

load方法需要一個loader作為參數(shù),返回一個通用類型T,在load方法中我,我們調(diào)用了另外一個Coroutine的創(chuàng)造者async()函數(shù),將會使用Background coroutine上下文在后臺線程中執(zhí)行任務(wù),注意這個方法還有另外一個參數(shù)start = CoroutineStart.LAZY,這意味著coroutine不會立即執(zhí)行,知道被調(diào)用為止。

coroutine接著會返回一個Defered<T>對象給調(diào)用者,這與我們之前的Job類似,但它也可以攜帶一個延遲值,如常規(guī)Java API中的JavaScript Promise或Future <T> ,更好的是他有一個await方法.

接下來我們定義另外一個擴展函數(shù)then() ,這次是在Deferen<T>上面定義,是我們上面的load方法返回的類型,它還將一個lambda作為參數(shù),命名為block,它將T類型的單個對象作為其參數(shù)。

infix fun <T> Deferred<T>.then(block: (T) -> Unit): Job {
 return launch(context = UI) {
 block(this@then.await())
 }
}

這個函數(shù)將使用launch()函數(shù)創(chuàng)建另一個Coroutine ,這次在主線程上運行。傳遞給此Coroutine的lambda(命名塊)將完成的Deferred對象的值作為其參數(shù)。我們調(diào)用await()來掛起這個Coroutine的執(zhí)行,直到Deferred對象返回一個值。

這里是coroutine變得如此令人印象深刻的地方。 await()的調(diào)用是在主線程上完成的,但是不會阻塞該線程的進一步執(zhí)行。它將簡單地暫停該函數(shù)的執(zhí)行,直到它準(zhǔn)備好,當(dāng)它恢復(fù)并將延遲值傳遞給lambda時。coroutine暫停時,主線程可以繼續(xù)執(zhí)行其他的事情。await函數(shù)是coroutine中的一個核心概念,是什么創(chuàng)造了整個事物如此有魔力。

load()函數(shù)中添加的生命周期觀察者將在我們的activity上調(diào)用onDestroy()后取消第一個coroutine。這也會導(dǎo)致第二個coroutine被取消,阻止block()被調(diào)用。

Kotlin Coroutine DSL

現(xiàn)在我們得到了兩個擴展函數(shù)和一個會處理coroutine被取消的類,讓我們來看看如何使用:

load {
 loadBitmapFromMediaStore(imageId, imagesBaseUri)
} then {
 imageView.setImageBitmap(it)
}

上面的代碼中,我們將lambda方法傳給load函數(shù),該函數(shù)調(diào)用loadBitmapFromMediaStore方法,該函數(shù)必須在后臺線程上執(zhí)行,直到該方法返回一個Bitmap,load方法的返回值是Deferred<Bitmap>

作為擴展函數(shù),then()方法使用infix聲明,盡管load方法中返回的是Deferred<Bitmap> ,但是將會傳送給then方法一個bitmap返回值,所以我們可以直接在then方法中調(diào)用imageView.setImageBitmap(it)

上面的代碼可以用于任何需要在后臺線程上發(fā)生的異步調(diào)用,以及返回值應(yīng)該返回到主線程的地方,就像上面的例子。它不像RxJava那樣可以編寫多個調(diào)用,但它更容易閱讀,可能會涵蓋很多最常見的情況?,F(xiàn)在你可以安全地做這樣的事情,而不必擔(dān)心在每個調(diào)用中造成context泄漏或處理線程;

load { restApi.fetchData(query) } then { adapter.display(it) }

then()和load()方法只不過是這個新庫的冰山一角,但是我確實希望在未來的基于Kotlin的Android庫中出現(xiàn)類似的東西,一旦coroutine版本達到穩(wěn)定版本。在此之前,您可以使用或修改上面的代碼,或者查看Anko Coroutines。我還在GitHub上發(fā)布了一個更完整的版本。 (https://github.com/ErikHellman/KotlinAsyncWithCoroutines (本地下載)).

總結(jié)

以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對腳本之家的支持。

相關(guān)文章

  • Java輸出多位小數(shù)的三種方法(附代碼)

    Java輸出多位小數(shù)的三種方法(附代碼)

    這篇文章主要給大家介紹了關(guān)于Java輸出多位小數(shù)的三種方法的相關(guān)資料,在實際工作中常常需要設(shè)定數(shù)字的輸出格式,如以百分比的形式輸出,或者設(shè)定小數(shù)位數(shù)等,需要的朋友可以參考下
    2023-07-07
  • 詳解Java如何優(yōu)雅的實現(xiàn)異常捕獲

    詳解Java如何優(yōu)雅的實現(xiàn)異常捕獲

    在一個優(yōu)秀的項目中一定少不了對程序流程良好的異常捕獲與日志打印,所以本文主要為大家介紹了如何優(yōu)雅的實現(xiàn)異常捕獲與日志打印輸出,有需要的可以參考下
    2023-09-09
  • 細數(shù)java中Long與Integer比較容易犯的錯誤總結(jié)

    細數(shù)java中Long與Integer比較容易犯的錯誤總結(jié)

    下面小編就為大家?guī)硪黄殧?shù)java中Long與Integer比較容易犯的錯誤總結(jié)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-01-01
  • Mybatis-plus null值更新不生效問題解決

    Mybatis-plus null值更新不生效問題解決

    在使用Mybatis-plus進行數(shù)據(jù)更新時,默認策略是NOT_NULL,即null值不會被更新到數(shù)據(jù)庫,解決方法包括設(shè)置全局field-strategy、對特定字段設(shè)置field-strategy或使用UpdateWrapper方式更新,下面就來介紹一下
    2024-10-10
  • 指定jdk啟動jar包的方法總結(jié)

    指定jdk啟動jar包的方法總結(jié)

    這篇文章主要給大家總結(jié)介紹了關(guān)于指定jdk啟動jar包的方法,文中通過實例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2023-07-07
  • springboot整合vue項目(小試牛刀)

    springboot整合vue項目(小試牛刀)

    這篇文章主要介紹了springboot整合vue項目(小試牛刀),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-09-09
  • mybatis-plus自動填充插入更新時間有8小時時差

    mybatis-plus自動填充插入更新時間有8小時時差

    本文主要介紹了mybatis-plus自動填充插入更新時間有8小時時差,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • java使用Runtime執(zhí)行系統(tǒng)命令遇到的問題

    java使用Runtime執(zhí)行系統(tǒng)命令遇到的問題

    這篇文章主要介紹了java使用Runtime執(zhí)行系統(tǒng)命令遇到的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Spring Cloud Gateway組件的三種使用方式實例詳解

    Spring Cloud Gateway組件的三種使用方式實例詳解

    Spring Cloud Gateway是 Spring 官方基于 Spring5.0 、 SpringBoot2.0 和 Project Reactor 等技術(shù)開發(fā)的網(wǎng)關(guān)旨在為微服務(wù)框架提供一種簡單而有效的統(tǒng)一的API 路由管理方式,統(tǒng)一訪問接口,這篇文章主要介紹了Spring Cloud Gateway組件的三種使用方式,需要的朋友可以參考下
    2024-01-01
  • 詳解Javaee Dao層的抽取

    詳解Javaee Dao層的抽取

    這篇文章主要介紹了詳解Javaee Dao層的抽取,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07

最新評論