iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 18
0
Mobile Development

30天,從0開始用Kotlin寫APP系列 第 18

Day 18 | Kotlin 中處理異步的好伙伴 - Coroutine

  • 分享至 

  • xImage
  •  

Application vs. Process vs. Thread vs. Coroutine

這些是作業系統( Operation System )中的基礎概念,用這張圖可以簡單區分他們

  • 程式(Application ) :一個 Application 就是開發者開發出來的程式碼,這時還沒載入到 Memory
  • 進程( Process ) :點開 Application ,將 Application 載入 Memory 中,就是 Process,在 Linux command line 上輸入 htop ,就可以看到目前有哪些 Process 正在執行中,並且 Process 之間是不能直接溝通的(如果可以任意呼叫到其他應用程式裏面的內容,那也有點太可怕了)
  • 線程( Thread )ProcessThread 的容器,一個 Process 中可以持有多個 ThreadThread 共享資源
  • 協程( Coroutine )Coroutine 一次只會執行一個 Job ,會透過頻繁切換 Job 達到類似異步的效果,需要的資源比開新的 Thread


Asynchronous Jobs

以昨天的例子說,如果採用 Synchronous 來處理的話,那會長的像這樣

fun fetchPirateList(): String {
    val response = pirateService.fetchPirateList()
    return response.body().toString()
}

那麼在第 6 行因為要等待 Server 回傳,因此就會卡住 Main thread ,而其他的任務也沒辦法拿到用戶可能就會看到卡住很久的畫面,因此我們需要做到的是讓這類型的任務跑在其他的 Thread 上(例如 IO thread ),讓 Main thread 可以去處理其他的工作
而且 Andorid OS 有一個機制是如果有人佔用 Main Thread 太久, App 就會 Crash 掉,相信剛開始寫 App 並且對非同步不熟的朋友應該都遇過很多次這樣的問題(就是在說我啦...)

Coroutine Basic

CoroutineScope(Dispatchers.Main).launch {
  val pirateListString = fetchPirateList() // Suspending function 跑在 I/O thread
  updatePirateTextView(pirateListString) // updatePirateTextView() 會跑在 Main Thread,做更新 UI
}

suspend fun fetchPirateList(): String = withContext(Dispatchers.IO) {
    // 從 Server 取得資料並回傳 PirateList String
    val response = pirateService.fetchPirateList()
    return response.body().toString()
}

Suspending Function

Suspend function 可以暫停協程的執行,這意味著它將等待直到 suspending function 恢復,接下來會一一講解

1. CoroutineScope

指的是 Coroutine 作用的範圍,所有的 Coroutine 都會執行在 CoroutineScope 中

  • CoroutineScope
    使用自定義 CoroutineContext 範圍,可根據需要定義 ThreadParent jobException handler
CoroutineScope(Dispatchers.Main + job + exceptionHandler).launch {
    ...
}
  • MainScope
    Main scope 通常都是在處理 UI 更新的任務或是 UI Component ,會透過 SupervisorJob() 在主線程上執行
public fun MainScope(): CoroutineScope = 
    ContextScope(SupervisorJob() + Dispatchers.Main)
  • GlobalScope
    GlobalScope 不局限於任何 Job ,協程會在整個 Application 生命週期內運行

2. CoroutineContext

指的是 Coroutine 作用的情境,也就是 Main thread 或是 IO thread 等

  • Dispatchers.Main
    等同於 Android 中的 Main thread

  • Dispatchers.Default
    使用共享的 Backend threads poolDispatchers.Default 默認使用的最大線程數等於 CPU 內核數

  • Dispatchers.IO
    Dispatchers.Default 共享線程,但是線程數受 kotlinx.coroutines.io.parallelism 限制,默認為 64 個線程或內核數(以較大者為準)

  • Dispatchers.Unconfined
    不局限於任何特定線程的協程調度程序,默認在當前線程中執行

3. Coroutine Builer

  • launch
    在不阻塞當前線程的情況下啟動新的協程

  • async and await
    AsyncCoroutineScope 的擴展,並且通常會與 Await 做搭配,透過 Await 會等待 Async 執行完之後才會開始執行,

4. Coroutine Body

在CoroutineScope中運行的代碼( Regular function 或 Suspending functions ),將暫停協程直到完成

結語

今天簡單的複習了 Coroutine 的部份,但其實也還沒完全了解,只能從字面上做解釋,還有很多更深入的部份還沒完全掌握好,今天寫的文章我覺得不是特別好,因此我會在之後了解更清楚,以及有更多使用上的心得後會在回頭更新這篇文章
明天可能會介紹 Flow 的部份, Flow 也是我近期才開始接觸的,昨天有提到他和 RxJava 常被拿來做比較,因此之後如果有機會碰到 RxJava 應該也會寫個文章來介紹喔

Reference


上一篇
Day 17 | 用 Kotlin 實作 MVVM 中的 Repository Layer
下一篇
Day 19 | Kotlin 完成基礎 MVVM 架構
系列文
30天,從0開始用Kotlin寫APP30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言