主頁 > 移動端開發 > Kotlin協程-從理論到實戰

Kotlin協程-從理論到實戰

2023-06-17 08:16:30 移動端開發

上一篇文章從理論上對Kotlin協程進行了部分說明,本文將在上一篇的基礎上,從實戰出發,繼續協程之旅,

從源頭說起

在Kotlin中,要想使用協程,首先需要使用協程創建器創建,但還有個前提——協程作用域(CoroutineScope),在早期的Kotlin實作中,協程創建器是一等函式,也就是說我們隨時隨地可以通過協程創建器創建協程,但在協程正式發布以后,協程創建器需要在協程作用域物件上才能創建了,Kotlin添加了協程作用域來實作結構化并發,什么是結構化并發呢,通俗地說就是正確實施多個協程監控、管理的能力,在實際業務中,我們可能需要創建多個協程物件來完成不同的作業,為了對這些不相關的協程管理起來,Kotlin引入了協程作用域,通過某個協程作用域創建的協程都會被它管理著,在條件滿足的時候,執行每個協程的取消作業或者結束自己,

為了方便我們直接上手,官方提供了MainScopeGlobalScope供我們使用,正如名字那樣,他們分別有不同的應用場景,前者比較適合用在UI相關的類中,而后者適用于在整個應用生命周期中都需要存活的類中,當然,對于Android開發者,其實我們有更好的選擇——使用ViewModel的Kotlin擴展,它不僅有著全部的協程作用域功能,開箱即用,而且還在onCleared方法中實作了自動取消,

創建協程

有了協程作用域,那我們來創建一個最簡單的協程吧,

viewModelScope.launch{
    //這里就是協程代碼啦啦啦啦
    delay(2000)
    System.out.println("Hello World")
}

launch創建并啟動了一個協程,協程啟動兩秒后,在控制抬列印了Hello World,然后協程就結束了(協程是有完整生命周期的),這個協程完成的作業有限,我們可以使用執行緒完成相同的功能:

thread {
            Thread.sleep(2000)
            System.out.println("Hello World")
        }

我們可以看到,除去構建函式,兩段代碼唯一的區別就是延遲函式——delayThread.sleep.從功能上看他們都是讓后面的代碼延遲執行,但是效果卻是不一樣的,前者不會阻塞執行緒,這段代碼其實是放在主執行緒里面執行的,但是它不會影響到UI的繪制,而后者假如把它放在主執行緒執行的話,應用會出現兩秒的無回應,Kotlin把這種不會阻塞當前執行緒執行的函式稱之為掛起函式,掛起函式可以在掛起點斷開與當前執行緒的聯系,讓執行緒空閑下來完成其他的操作,當條件滿足后,掛起函式重新在掛起點恢復,接著往下執行后面的代碼,

還有個小問題沒有解決,在上一篇文章中,我曾經說過,掛起函式只能在掛起函式中執行,既然delay是掛起函式,那么反推,我們的代碼塊也應該是個掛起函式,而這個掛起函式就是所謂的協程體,

讓協程跨執行緒作業

如果你看到上面的代碼,然后轉手在協程體里面寫個網路請求的話,你會發現,你的應用崩潰了,這是怎么回事呢?因為協程雖然不會阻塞主執行緒,但是主執行緒是不允許進行網路請求的,如果這時你就急著下了協程沒啥用的結論,那么你就膚淺了,讓我們稍微改一改上面的代碼,讓它運行在子執行緒吧,

viewModelScope.launch (Dispatchers.IO){
    //這里就是協程代碼啦啦啦啦
    delay(2000)
    System.out.println("Hello World")
}

很好,現在協程體里面的網路請求可以順利執行了,但是很快有讀者就會發現新問題了——我怎么把網路請求的結果傳回主執行緒呢,難不成還搞個Handler,那和直接使用執行緒有什么區別,辣雞協程,嘿,別急,這個協程其實也為客官處理好了,讓我們再次改造一下代碼:

viewModelScope.launch (Dispatchers.IO){
    //這里就是協程代碼啦啦啦啦,這里是在子執行緒執行的代碼哦
    //假裝這個是網路請求吧
    delay(2000)
    withContext(Dispatchers.Main) {
        //哦豁豁,這里竟然運行在主執行緒哦
        System.out.println("Hello World")
    }
}

很好,我們可以愉快地使用協程處理網路請求了,那么這些魔法是怎么發生的呢,停下腳步,我們來重新審視一下上面的代碼,

首先,相比于最開始的代碼,我們的代碼里多了兩個物件,一個方法呼叫,首先我們來看那兩個物件,從名字中我們不難猜到它就是調度執行緒的,
Kotlin提供了四個常用的實作

  • Default,它是標準協程構建者默認使用的調度器,使用共享的執行緒池作業,適用于計算型的任務;

  • Main,它是代表UI執行緒的調度器,通常來說只有一個執行緒,使用這個調度器就可以直接在協程中操作UI;

  • Unconfined,它沒有限定執行緒范圍,它在哪個執行緒中被呼叫就會在哪個執行緒里執行完初始的代碼,直到遇到掛起函式,隨后它會使用掛起函式指定的調度器恢復,這個程序可以一直持續下去,

  • IO,是用來承載阻塞的IO操作的,如檔案讀寫,網路連接等,是我們比較常用的調度器,

所以那兩個調度器物件是讓協程切換作業環境的魔法,接下來還有一個方法呼叫沒有解釋,withContext的作用是將當前的協程調度器切換到指定的調度器上,用這個調度器接著執行構建塊中的代碼,同時它也是一個掛起函式,提到掛起函式,我們就該想到,它是可恢復的,所以當這個掛起函式的代碼塊執行完成之后,它會自動恢復成原來的調度器,接著往下執行,

用協程串聯兩個異步操作

在專案開發中,還有一種常見的應用場景,客戶端需要先請求一些配置資訊,然后利用配置資訊再請求真正的內容資訊,這個程序描述起來是串行的,但是代碼寫起來卻是割裂的,需要在第一個網路請求的回呼中處理和發起第二個請求,然后在第二個回呼中獲取真正需要展示的資料,可能這個程序還會加個存庫,或者觸發另外請求的作業,那么完了,這代碼沒法看了,這放在以前,這種情況通常會使用RxJava,但是RxJava的代碼可讀性也還是差點意思,那么Kotlin協程可以寫成什么樣呢?

viewModelScope.launch(Dispatchers.IO) {
            val retrofit=Retrofit.Builder().build()
            val apiUser=retrofit.create(APIUser::class.java)
            val user=api.current()
            val detail=api.userDetail(user.id)
            withContext(Dispatchers.Main) {
                userLiveData.value=https://www.cnblogs.com/honguilee/archive/2023/06/16/detail
            }
        }

這和我們寫一般的同步代碼一摸一樣,沒有回呼,也不需要付出其他代價,這個程序甚至可以一直加下去,其實我覺得這個才是協程的真正威力,

讓多個協程一起作業

我們繼續復雜化使用場景——我在做一個多端使用的筆記App,現在用戶打開了某一個已存在的筆記,為了讓用戶能快速瀏覽到上一次的操作資訊,一方面我需要從檔案中讀取上一次操作的結果,另一方面我要拉取遠程的操作結果,然后對兩個結果合并,決定最終的展示資料,考慮到這兩個操作其實是并行的,上面我們讓協程串聯起來的思路已經不適用了,因為協程里面的操作都是串行的,既然一個協程解決不了,我們再加一個協程可不可以呢?看著好像是可以,但是,協程操作的結果我們怎么獲取到呢?查閱API,我找到了另一個協程構建器async,它會回傳一個協程物件,然后通過await方法獲取到協程的計算結果,思路來了,我們馬上動手

 val fileResult=viewModelScope.async(Dispatchers.IO) {
             //假裝是讀檔案的代碼吧
             1
         }
 val networkResult=viewModelScope.async(Dispatchers.IO) {
     //也是假裝是網路請求的代碼
     2
 }
 val fResult=fileResult.await()
val rResult=networkResult.await()
val result=if(fResult>rResult){
    fResult
}else{
    networkResult
}

然后你就會發現報錯了,await是掛起函式,看來兩個協程還完成不了,要三個,所以,讓我們創建第三個協程吧

 //前面的兩個協程不變
 viewModelScope.launch {
     val fResult=fileResult.await()
     val rResult=networkResult.await()
     val result=if(fResult>rResult){
         fResult
     }else{
         networkResult
     }
}

這就是協程間通信的基本寫法啦,從這個基礎之上,甚至還能衍生出更復雜的版本,但是萬變不離其宗,都可以參考這種思路完成,

協程的取消

正如之前提到的一樣,協程有著類似于執行緒的完整生命周期,包括創建,激活,完成中(取消中),已完成(已取消),剛才我們的示例都是正常狀態,協程完成作業后會自動結束,但協程的另一條取消流程我們還沒有提到,協程有自己的取消API——cancel可供使用,我們只需要保存好協程創建者回傳的協程物件就行了,當然更常見的還是文章開篇提到的使用協程作用域取消,這個操作會取消所有的協程,

總結

本篇文章從協程創建開始,講到了怎樣用協程寫出異步代碼,怎么讓多個協程共同作業,雖然覆寫了很大一部分使用場景,但是依然還有遺漏,由于篇幅限制,遺漏部分將在下一篇博文中繼續講解,希望大家持續關注,

青山不改,綠水長流,咱們下期見!

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/555429.html

標籤:其他

上一篇:Kotlin協程-從一到多

下一篇:返回列表

標籤雲
其他(161178) Python(38236) JavaScript(25504) Java(18244) C(15237) 區塊鏈(8271) C#(7972) AI(7469) 爪哇(7425) MySQL(7256) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5875) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4601) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2436) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) HtmlCss(1968) 功能(1967) Web開發(1951) C++(1941) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • Kotlin協程-從理論到實戰

    > 上一篇文章從理論上對Kotlin協程進行了部分說明,本文將在上一篇的基礎上,從實戰出發,繼續協程之旅。 ### 從源頭說起 在Kotlin中,要想使用協程,首先需要使用協程創建器創建,但還有個前提——協程作用域(`CoroutineScope`)。在早期的Kotlin實作中,協程創建器是一等函式 ......

    uj5u.com 2023-06-17 08:16:30 more
  • Kotlin協程-從一到多

    > 上一篇文章,我介紹了Kotlin協程的創建,使用,協作等內容。本篇將引入更多的使用場景,繼續帶你走進協程世界。 ### 使用協程處理異步資料流 常用編程語言都會內置對同一型別不同物件的資料集表示,我們通常稱之為容器類。不同的容器類適用于不同的使用場景。Kotlin的`Flow`就是在異步計算的需 ......

    uj5u.com 2023-06-17 08:16:25 more
  • 【有獎調研】HarmonyOS新物種,鴻蒙流量新陣地——元服務邀你來答

    “聊技術無話不談,一起來吹吹元服務!暢聊你對元服務的想法,說不定,你就能撬動元服務的爆發增長!” 元服務(即原子化服務)是華為“輕量化”服務的新物種,可提供全新的服務和互動方式,讓應用化繁為簡,讓服務觸手可及!基于鴻蒙萬能卡片,元服務可實作應用功能在桌面“永遠打開”,實作智能推薦、服務直達! 而在元 ......

    uj5u.com 2023-06-17 08:16:19 more
  • Kotlin協程-從理論到實戰

    > 上一篇文章從理論上對Kotlin協程進行了部分說明,本文將在上一篇的基礎上,從實戰出發,繼續協程之旅。 ### 從源頭說起 在Kotlin中,要想使用協程,首先需要使用協程創建器創建,但還有個前提——協程作用域(`CoroutineScope`)。在早期的Kotlin實作中,協程創建器是一等函式 ......

    uj5u.com 2023-06-17 08:15:56 more
  • Kotlin協程-從一到多

    > 上一篇文章,我介紹了Kotlin協程的創建,使用,協作等內容。本篇將引入更多的使用場景,繼續帶你走進協程世界。 ### 使用協程處理異步資料流 常用編程語言都會內置對同一型別不同物件的資料集表示,我們通常稱之為容器類。不同的容器類適用于不同的使用場景。Kotlin的`Flow`就是在異步計算的需 ......

    uj5u.com 2023-06-17 08:15:51 more
  • 【有獎調研】HarmonyOS新物種,鴻蒙流量新陣地——元服務邀你來答

    “聊技術無話不談,一起來吹吹元服務!暢聊你對元服務的想法,說不定,你就能撬動元服務的爆發增長!” 元服務(即原子化服務)是華為“輕量化”服務的新物種,可提供全新的服務和互動方式,讓應用化繁為簡,讓服務觸手可及!基于鴻蒙萬能卡片,元服務可實作應用功能在桌面“永遠打開”,實作智能推薦、服務直達! 而在元 ......

    uj5u.com 2023-06-16 08:48:47 more
  • 100個物聯網專案(基于ESP32)1ESP32的基礎

    ## 1-NodeMCU、ESP32的基礎 ### 簡介 NodeMCU是一個開源的IoT(物聯網)平臺,包括在樂鑫的ESP8266 Wi-Fi SoC上運行的韌體和基于ESP-12模塊的硬體。它是由一樂鑫在2014年創建的,他們希望為物聯網專案提供低成本和靈活的平臺。ESP32是低成本的微芯片,具 ......

    uj5u.com 2023-06-16 08:30:36 more
  • 推送服務接入指導(HarmonyOS篇)

    訊息推送作為App運營日常使用的用戶促活和召回手段,是與用戶建立持續互動和連接的良好方式。[推送服務](https://developer.huawei.com/consumer/cn/hms/huawei-pushkit?ha_source=hms1)(Push Kit)是華為提供的訊息推送平臺, ......

    uj5u.com 2023-06-16 08:30:25 more
  • Kotlin協程-那些理不清亂不明的關系

    > Kotlin的協程自推出以來,受到了越來越多Android開發者的追捧。另一方面由于它龐大的API,也將相當一部分開發者拒之門外。本篇試圖從協程的幾個重要概念入手,在復雜API中還原出它本來的面目,以全新的角度帶讀者走進Kotlin協程世界。 ### 什么是協程 在很多有關協程的文章中,描述協程 ......

    uj5u.com 2023-06-16 08:30:20 more
  • 社交直播語聊場景解決方案(一)商業化探索

    在過去幾年的直播行業創業風口期中,直播的用戶關注度瘋狂增長,但用戶質量卻參差不齊。隨著用戶新鮮感一過,流失率變得相當嚴重,各大平臺都在竭盡全力防御。然而,留住“湊熱鬧”的非直播受眾用戶并不是最關鍵的問題,而是要找到適合真實直播受眾用戶的商業化道路,才能保證行業的穩定繁榮。因此,我們需要探索有效的商業... ......

    uj5u.com 2023-06-16 08:30:15 more