iT邦幫忙

2021 iThome 鐵人賽

DAY 29
0
Software Development

Coroutine 停看聽系列 第 29

Day29:複習 Channel、Flow

Coroutine 中如果要執行非同步程式,則需要把耗時任務寫在 suspend 函式中,並且在一個 CoroutineScope 中來執行,而建立 CoroutineScope 的方式則是可以使用 launch、async。

如果我們有很多 suspend 函式想要同時開始執行,並且我們希望能夠在執行的時候能夠按照順序產出結果, Coroutine 提供了兩種方法,一種為 Channel ,另一種則是 Flow。

Channel

我們在 CoroutineScope 中使用 Channel ,並且使用 send() 來將獲得的值傳出去。在 Channel 的另一頭,也就是接收端,我們使用 receive() 來接收由 send() 傳送出來的值。

我們使用 Channel 的時機點是在我們有多個 suspend 函式想要執行,並且我們希望在其他的 CoroutineScope 接收這個值。

如同前面所說,Channel 是一種有順序的傳送方式,它的順序是採取先進先出(FIFO),當我們使用 send() 將某個值傳進 Channel 中時,在另一個 CoroutineScope 中呼叫 receive() 就會將該值取出。如果有多個值依序呼叫 send(),那麼在另外一頭呼叫 receive() 時就會按照順序出來,這邊需要注意的是,呼叫 receive() 的次數必須要與 send() 相同,不然該 Channel 就會一直 suspend ,直到正確數量的 receive() 被呼叫。

Channel 提供了多種存放方式:

  • RENDEZVOUS
  • CONFLATED
  • UNLIMITED
  • BUFFERED
  • 其他

預設是 RENDZVOUS,是一種沒有 buffer的 channel,使用這種 channel 必須要成雙成對,也就是說呼叫 send() 就必須要呼叫 receive()。

CONFLATED 則是 buffer 大小只有一個,所以後面新的值就會把舊的值給蓋掉。

UNLIMITED 則是有無限容量的 channel,所以呼叫 send() 的時候不會因為 buffer 的容量滿了而讓後面還沒有執行的 send() 被 suspend。

BUFFERED 則是可以根據我們的需求給予固定大小的 buffer,當buffer 滿了的時候,就會suspend send() 函式。

Flow

與 Channel 不同,Flow 是屬於 code stream,也就是說 flow 只有當呼叫 terminal operator 的時候,才會執行,而在 terminal operator 之前,可以有多個 Intermediate operator (中間運算子),我們可以利用這中間運算子將這些值在輸出之前改變其樣貌。

要怎麼把值放入 flow 中呢?我們使用 emit() 將值射入 flow 中,並使用 collect 將全部的值取出。如我們前面所說的,我們可以運用中間運算子進行數值的處理,最後才使用終端運算子把結果取出。而這邊的終端運算子不只有 collect。

我們可以使用 flowOn 來使用不同的 Dispatchers,選擇不同的執行緒。

SharedFlow 以及 StateFlow

另外,有兩種特殊的 flow,一個為 SharedFlow,另一個則是 StateFlow。

這兩種 Flow 與原本的 Flow 不同,它們是屬於 hot stream。

用處是什麼呢?如果我們希望把 Flow 的值同時通知給其他使用者,我們就可以使用。有兩種方式使用,一種是將原本的 Flow 直接經過轉換變成 SharedFlow 或是 StateFlow,另一種方式則是使用 MutableXXXFlow的版本,來將值填入,再將 MutableXXXFlow 轉成 XXXFlow,那麼我們只要更新 MutableXXXFlow,其他使用者調用 XXXFlow 的 collect,就可以把值取出。

而根據 Flow 保存的值的方式不同,有分這兩種 Flow,主要的區別在於 SharedFlow 可以有比較大的 buffer,所以可以存放比較多的內容,當有新的用戶加入時,就可以把最新的資料都倒給它,相對的,StateFlow 則是 buffer 的容量只有 一,也就是說每次的新值加入時,都會把原本的值蓋掉,而新的用戶加入時,也只會得到最新的一筆資料。所以在 Android 的使用上會被提出用來更換 LiveData。


好了,Channel 以及 Flow 的複習到這邊就差不多了,如果有問題可以看看前面的文章,或是可以跟我討論 XD

那麼本篇就到這邊告一段落了。

特別感謝

Kotlin Taiwan User Group

Kotlin 讀書會


上一篇
Day28:複習 Coroutine
下一篇
Day30:The end is not the end
系列文
Coroutine 停看聽30

尚未有邦友留言

立即登入留言