亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

利用Kotlin的協程實現簡單的異步加載詳解

2024-07-21 23:03:44
字體:
來源:轉載
供稿:網友

前言

眾所周知在android中當執行程序的耗時超過5秒時就會引發ANR而導致程序崩潰。由于UI的更新操作是在UI主線程進行的,理想狀態下每秒展示60幀時人眼感受不到卡頓,1000ms/60幀,即每幀繪制時間不應超過16.67ms。如果某項操作的耗時超過這一數值就會導致UI卡頓。因此在實際的開發中我通常把耗時操作放在一個新的線程中(比如從網絡獲取數據,從SD卡讀取圖片等操作),但是呢在android中UI的更新只能在UI主線程中進行更新,因此當我們在非UI線程中執行某些操作的時候想要更新UI就需要與UI主線程進行通信。在android中google為我們提供了AsyncTask和Handler等工具來便捷的實現線程間的通信。有許多的第三方庫也為我們實現了這一功能,比如現在非常流行的RxJava庫。在本篇文章中呢我想給大家分享的是使用Kotlin的Coroutine(協程)來實現耗時操作的異步加載,現在有RxJava這么屌的庫我們為什么還要了解這個呢?Kotlin如今已是android的官方開發語言了解他里邊的異步相關的操作是很有必要的。本文只講解Coroutine的基本使用方法,并不作深入底層的研究,我將以一個加載圖片的例子來向您展示Coroutine的基本使用方法。

使用Coroutine之前的初始配置

首先我們使用android studio 新建一個項目,并在新建項目的時候勾選【Include Kotlin support】,就像下邊這樣

kotlin,協程,協程使用,異步

項目創建成功后,我們需要在build.gradle文件中的android配置模塊下面增加如下的配置

kotlin/282278.html">kotlin { experimental { coroutines 'enable' }}

然后在build.gradle文件中添加如下的依賴

implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:0.20' implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:0.20'

完整的配置情況如下:

kotlin,協程,協程使用,異步

經過上邊的步驟Coroutine的配置就已經完成了。接下來我們就可以使用Coroutine了。

實現你的第一個Coroutine程序

現在我們來開始編寫我們的第一個Coroutine例子程序,這個程序的主要功能就是從手機媒體中加載一張圖片,并把它顯示在一個ImageView中。我們先來看看在未使用Coroutine之前使用同步的方式加載圖片的代碼如下:

val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)imageView.setImageBitmap(bitmap)

在上邊的代碼中我們從媒體讀取了一張圖片并把它轉化成Bitmap對象。因為這是一個IO操作,如果我們在UI主線程中調用這段代碼,將可能導致程序卡頓或產生ANR崩潰,所以我們需要在新開的線程中調用下邊的代碼

val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, uri)

接著我們需要在UI線程中調用下邊的代碼來顯示加載的圖片

imageView.setImageBitmap(bitmap)

為了實現這一功能在傳統的android程序中我們需要使用Handler或AsyncTask將結果從非UI主線程發送到UI主線程進行顯示,我們需要編寫許多額外的代碼。并且這些代碼的可讀性也不是十分的友好。下邊我們來看看使用Kotlin的Coroutine來實現圖片的加載的代碼,如下:

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

我們先忽略返回值job,我們稍后會進行介紹,在這兒我們關心的事情是launch函數和參數Background與UI。與之前使用同步的方式加載圖片相比唯一的不同就在于這兒我們調用了lauch函數。lauch()創建并啟動了一個協程,這兒的參數Background是一個CoroutineContext對象,確保這個協程運行在一個后臺線程,確保你的應用程序不會因耗時操作而阻塞和崩潰。你可以像下邊這樣定義一個CoroutineContext:

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

他將使用含有兩個線程的線程池來執行協程里邊的操作。在第一個協程里邊我們又調用了launch(UI)創建并啟動了一個新的協程,這兒的UI并不是我們自己創建的,他是Kotlin在Android平臺里邊預定義的一個CoroutineContext,代表著在UI主線程中執行協程里邊的操作。所以我們將更新程序界面的操作imageView.setImageBitmap(bitmap)放在了這個協程里。通過這兒的例子代碼你會發現在kotlin里邊使用協程來實現線程間的通信和切換非常的簡單,比RxJava還簡單??瓷先ゾ透銓懲降姆绞降拇a一樣。

取消協程

在上邊的例子中我們返回了一個Job類型的對象job。通過調用job.cancel()我們能夠取消一個協程。例如當我們退出當前Activity的時候,圖片還沒有加載完。這個時候我們就可以在onDestroy中調用job.cancel()來取消這個未完成的任務。這與我們使用Rxjava時調用dipose()或使用AsyncTask時調用cancel() 來取消未完成的操作的作用是一樣的。

LifecycleObserver

android 架構組件( Android Architecture Components )里邊引入了許多非常好的東西,比如:ViewModel, Room 和 LiveData以及Lifecycle API。給予我們一種非常安全簡便的方式監聽Activity和Fragment的生命周期變化。接下來我們將使用他們來對之前加載圖片的例子進行改進,利用lifecycle對Activity生命周期進行監聽并做出相應的處理(監聽到Activity調用onDestroy()時自動取消后臺任務)。

我們定義如下的代碼來使用協程:

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

我們也創建了LifecycleOwner的一個擴展函數:

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

在這個函數里邊有許多新的東西,即使看上去感到疑惑也不要緊,我們會一步一步的對其進行講解。我們在所有實現LifecycleOwner接口的類中擴展了一個load函數。也就是說當我們使用支持庫的時候我們可以在Activity或Fragment中直接調用這個load函數(支持庫里邊的AppCompatActivity和Fragment實現了LifecycleOwner接口)。為了能夠在這個函數里邊訪問lifecycle成員添加CoroutineLifecycleListener作為一個觀察者。

load()函數使用名為loader的lambda表達式作為參數(這個lambda表達式返回一個泛型類型T),在load()函數里邊我們調用了名叫async的函數,這個函數的作用也是用于創建一個協程。它使用Background作為上下文。注意第二個參數start = CoroutineStart.LAZY。它的意思是不會立即啟動一個協程。直到你顯示的請求他返回一個值的時候它才會啟動,稍后你會看到具體怎樣做。這個協程返回了一個Deferred<T>對象到調用者。它與我們之前提到的job對象是類似的,但是他可以攜帶一個延遲的值,類似于JavaScript 中的Promise或Java APIs中的Future<T>

接下來我們定義Deferred<T>類(前面我們在load函數中返回的類型)的一個擴展函數then() ,它也使用一個名叫block的lambda表達式作為參數。這個lambda表達式以T類型的對象作為參數。具體代碼如下:

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

這個函數使用launch()創建了另外一個協程,這個新的協程將運行在程序的主線程中。我們在這個新的協程中調用了then函數中傳入的名叫block的lambda表達式并使用await()函數作為它的參數。await()是在主線程中調用的,但是他并不會阻塞主線程的執行,它將掛起這個函數,主線程可以繼續做其他的事情。當值從其他協程中返回的時候,他將被喚醒并將值從Deferred傳遞到這個lambda中。掛起函數(Suspending functions)是協程中最主要的概念。

一旦Activity的onDestroy方法被調用的時候,我們在load()函數中添加的lifecycle觀察者將會取消第一個協程,也會使第二個協程被取消,避免block()被調用。

Kotlin Coroutine DSL

上邊我們定義了兩個擴展函數和一個用于取消協程的類,讓我們來看看如何使用它們,代碼如下:

load { MediaStore.Images.Media.getBitmap(contentResolver,uri)} then { imageView.setImageBitmap(it)}

在上邊的代碼中我們傳遞一個lambda到load()函數中,在這個lambda中調用了loadBitmapFromMediaStore()函數運行在一個后臺進程中。一旦loadBitmapFromMediaStore()函數返回Bitmap,load()函數將返回Deferred<Bitmap> 。擴展的函數then()是被infix修飾的,因此當Deferred<Bitmap>返回之后我們可以使用上面那種奇特的語法調用它。我們傳遞到then()中的lambda將接收到一個Bitmap對象。因此我們可以簡單的調用imageView.setImageBitmap(it)顯示這個Bitmap。

上邊的代碼可以被應用到任何別的需要使用異步調用并將值轉遞到主線程的操作中。和RxJava這種框架比起來Kotlin的協程可能沒有它那么強大。但是Kotlin的協程可讀性更強,也更簡單?,F在你可以安全的使用它來執行你的異步操作了,再也不用擔心內存泄漏的發生了。如下是將上邊的代碼用于從網絡加載數據并顯示的例子:

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

以上就是本篇文章所要分享的全部內容,希望能夠對你有所幫助。如果你發現文章中有不對的地方也歡迎你幫忙指出,以便我做出及時的更正。

源碼地址: https://github.com/chenyi2013/CoroutineDemo (本地下載)

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對VeVb武林網的支持。

參考文章:

https://developer.android.com/topic/libraries/architecture/lifecycle.html

https://kotlinlang.org/docs/reference/coroutines.html

https://hellsoft.se/simple-asynchronous-loading-with-kotlin-coroutines-f26408f97f46


注:相關教程知識閱讀請移步到kotlin教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产一区二区三区日韩欧美| 中文字幕av一区| 久久久久国产精品免费| 欧美性猛交xxxx富婆弯腰| 日韩在线免费高清视频| 日韩中文字幕不卡视频| 色琪琪综合男人的天堂aⅴ视频| 国产成人精彩在线视频九色| 欧美第一黄网免费网站| 中日韩美女免费视频网站在线观看| 欧美高清自拍一区| 日本高清视频一区| 欧美激情精品久久久久久蜜臀| 国产精品高潮粉嫩av| 亚洲欧美另类国产| 俺去了亚洲欧美日韩| 日韩亚洲精品电影| 欧美激情亚洲一区| 色综合久久悠悠| 久久久久久久激情视频| 欧美激情a∨在线视频播放| 久久视频在线观看免费| 日韩在线不卡视频| 欧美日韩国产精品一区二区三区四区| 少妇精69xxtheporn| 国产精品久久久91| 久久精品国亚洲| 国产日本欧美一区二区三区| 91av视频在线免费观看| 国产日韩精品入口| 欧美精品久久久久久久免费观看| 91亚洲国产成人久久精品网站| 日韩欧美亚洲成人| 日韩在线观看你懂的| 国产精品日韩av| 18久久久久久| y97精品国产97久久久久久| 黑丝美女久久久| 亚洲国产中文字幕久久网| 欧美午夜www高清视频| 亚州成人av在线| 亚洲区一区二区| 国产亚洲欧洲高清一区| 岛国精品视频在线播放| 91久久精品在线| 亚洲视频精品在线| 一区二区三区久久精品| 久久久影视精品| 欧美一级黑人aaaaaaa做受| 亚洲精品之草原avav久久| 日韩亚洲一区二区| 成人福利视频在线观看| 在线观看精品国产视频| 亚洲91精品在线观看| 国产亚洲精品久久久久久777| xxx一区二区| 亚洲人成啪啪网站| 欧美另类精品xxxx孕妇| 亚洲欧美制服另类日韩| 国产精品v片在线观看不卡| 97久久精品国产| 亚洲欧美日韩国产中文专区| 欧美一区二区大胆人体摄影专业网站| 欧美肥老太性生活视频| 久久久久久97| 亚洲欧洲美洲在线综合| 亚洲欧美国产精品久久久久久久| 亚洲性视频网站| 国产91精品高潮白浆喷水| 黑人巨大精品欧美一区二区一视频| 亚洲国产私拍精品国模在线观看| 日韩免费观看av| 亚洲人成电影在线| 国产91色在线免费| 国产成人精品999| 九九热99久久久国产盗摄| 国产精品香蕉国产| 国产亚洲免费的视频看| 精品无人区太爽高潮在线播放| 亚洲精品456在线播放狼人| 国产成人精品视频| 日韩美女中文字幕| 538国产精品视频一区二区| 欧洲美女7788成人免费视频| 91精品国产91久久久久福利| 国产成人在线视频| 欧美精品激情在线| 国产一区私人高清影院| 亚洲电影免费在线观看| 欧美国产精品va在线观看| 久久久国产视频| 粗暴蹂躏中文一区二区三区| 久久九九热免费视频| 91精品国产成人| 欧美激情国产高清| 欧美成人性生活| 亚洲精品国精品久久99热| 国产午夜精品一区二区三区| 久久亚洲精品毛片| 伊人亚洲福利一区二区三区| 91九色国产视频| 亚洲国产91色在线| 亚洲一区二区黄| 视频在线观看99| 性色av一区二区三区免费| 亚洲欧美一区二区三区四区| 俺去亚洲欧洲欧美日韩| 欧美大片欧美激情性色a∨久久| 欧美高清视频在线观看| 国内精品久久久久影院 日本资源| 国产一区二区色| 欧美专区在线观看| 国产精品v日韩精品| 久久综合久中文字幕青草| 欧美激情va永久在线播放| 欧美激情视频在线免费观看 欧美视频免费一| www.国产精品一二区| 国产成人精品久久久| 日韩精品中文字| 在线精品91av| 亚洲精品久久在线| 在线成人中文字幕| 欧美黄色片在线观看| 97在线精品国自产拍中文| 北条麻妃一区二区在线观看| 国产91精品视频在线观看| 亚洲va欧美va国产综合久久| 国产精品丝袜一区二区三区| 91精品视频免费| 成人xxxxx| 日韩激情视频在线播放| 奇门遁甲1982国语版免费观看高清| 欧美激情视频在线免费观看 欧美视频免费一| 欧美日韩一区二区三区在线免费观看| 亚洲欧美在线一区二区| 国产一区二区三区在线免费观看| 欧美激情亚洲精品| 亚洲女同性videos| 亚洲精品v欧美精品v日韩精品| 国产午夜精品一区理论片飘花| 欧美贵妇videos办公室| 欧美在线一区二区视频| 国产在线观看精品一区二区三区| 91视频国产一区| 亚洲国产精品免费| 亚洲免费av网址| 国产精品一区二区电影| 中文字幕欧美日韩va免费视频| 国产亚洲欧美日韩美女| 韩国三级日本三级少妇99| 欧美有码在线观看| 欧美电影《睫毛膏》| 91视频8mav| 亚洲色图色老头| 色综合天天综合网国产成人网| 久久精品免费电影| 亚洲精品视频在线播放| 精品国产91久久久| 国产区精品在线观看| 成人午夜小视频| 成人在线观看视频网站| 久久艹在线视频| 精品国产一区二区三区久久久| 中文字幕精品网|