[Android] Coroutines Hot Flow:Show me the code.(2/3)

Connie Lin
May 12, 2022

這是介紹 Coroutines Hot Flow 的系列文第二篇。在上一篇文章中,有聊到冷流與熱流的區別,也應該算是很詳盡、稍嫌囉唆的(?),用例子介紹了 SharedFlow 的幾種基本設定。如果還沒看過,請先服用:

而工程師,終究是要寫程式碼的,讓我們開始吧。

挖苦挖苦!

通常資料的提供方會是一個 Repository。與 LiveData 一樣,為了做到資料保護與職責分明,要在 Repository 內分別為生產者與訂閱者產生 Mutable 與 Immutable 的實體,並在類別內部向 MutableSharedFlow emit 資料。

任何一個需要這個資料的對象 — 就來個 WhateverViewModel 吧 ,會需要取得 MessageRepository.messageFlow 的 reference 來收集資料。

超級無敵簡單的寫法就完成了呢 (゜◇゜)!!(安妮雅驚訝.jpg

等等,我說那個 StateFlow 呢

上一篇文章輕描淡寫了 StateFlow 是 SharedFlow 的客製版,其特性又與 LiveData 相似,但似乎還沒有好好的來介紹過它。在創建實體時,會發現它要求在建構子傳入 value。

官方文件提到,建立 MutableStateFlow(initialValue) 其實就等同於對 SharedFlow 做了下面這些設定:

StateFlow 一開始就會 emit 預設值,並且設定為 replay = 1,所以 StateFlow 中永遠都存放著一筆資料。

因為 BufferOverflow.DROP_OLDEST 的特性,生產者想要修改資料的話,可以直接做 setValue,而不用在 Coroutine Scope 中做異步的 emit,因為結果而言會是一樣的。

要特別注意的是,StateFlow 額外做了 distinctUntilChanged() 。這意味著如果要更新資料,要注意不能直接修改舊有資料的實體,而是要創建一個新的實體,以避免被忽略掉。

StateFlow 基本特性以及可以透過 setValue 賦值的方式,看起來都和 LiveData 很像。最大的差異點在於 LiveData 並沒有強制要給預設值,所以即便將資料型別設定為 non-null,還是有可能拿到 null,State Flow 就安全多了。

StateFlow 如其名,適合放置「唯一而最新的」的資料。不像 SharedFlow 的資料介於有和沒有之間,StateFlow 一定會給予一個最新的狀態,有可能是 Loading、Success 或 Error,通常可以用 Sealed Class 把所有狀態給包裝起來。

下面一樣是 MessageRepository 的例子,我將預設狀態設為 Loading,並且依據不同的資料結果,分別將 value 設為 Success 或是 Error。這當然只是個簡陋的例子,不過還是可以從中感受到他與 SharedFlow 用法上的差異吧?

沒想到一下就寫完第二集了,簡短到還以為一切就是這麼單純無害呢。

不過往往都是在實際使用,或是案例變複雜時,才發現前方有詐。那就富奸一下,在這個系列的下一篇再來好好聊聊關於 SharedFlow 與 StateFlow ,那些不可不慎的事情吧。

--

--