實(shí)戰(zhàn) | 在 Room 中使用 Flow

△ Room 中對 Flow 的支持

Jetpack Room 對協(xié)程的支持越來越豐富: Room 2.1 版本增加了對協(xié)程的支持,并加入了一次性 (one-shot) 的讀寫操作,Room 2.2 我們通過 Flow 為讀操作加入了可觀察性,當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)有變化時它可以使您收到通知。

△ Room 支持異步 query 操作

Flow 實(shí)戰(zhàn)

假設(shè)我們有一個記錄小狗信息的數(shù)據(jù)庫,它的 name 字段是主鍵 (primary key),所以在數(shù)據(jù)庫中不可能同時有兩個 name 字段相同的數(shù)據(jù),也就是每只小狗都是唯一的。

@Entity
data class Dog (
    @PrimaryKey val name: String,
    val cuteness: Int,
    val barkingVolume: Int
)

為了從數(shù)據(jù)中獲取一個包含所有小狗信息的總表,我們在 DAO 中編寫如下 query 語句:

@Query("SELECT * FROM Dog")
fun getAllDogs(): List<Dog>

因?yàn)樾」返慕新?,也就是字?barkingVolume 會隨著時間變化,并且我們想確保 UI 展示的內(nèi)容是最新的。因此我們希望,當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)有變化時,可以通知到我們: 比如新增,刪除,或者是更新了數(shù)據(jù)。

為了實(shí)現(xiàn)這個功能,我們通過更新 query 操作返回一個 Flow 對象。

@Query("SELECT * FROM Dog")
fun getAllDogs(): Flow<List<Dog>>

就像這樣,每當(dāng)數(shù)據(jù)庫中的數(shù)據(jù)有更新時,會重新派發(fā)存有小狗信息的總表。例如,假設(shè)我們的數(shù)據(jù)庫中存有如下數(shù)據(jù):

(Frida, 11, 3)
(Bandit, 12, 5)

第一次調(diào)用 getAllDogs 時 Flow 派發(fā)的數(shù)據(jù)如下:

[(Frida, 11, 3), (Bandit, 12, 5)]

如果小狗 Bandit 比較興奮,那它的叫聲也會變大,也就是字段 barkingVolume 更新為 6: (Bandit,12,6),這時候 Flow 會重新派發(fā)最新數(shù)據(jù),所以整個列表被更新為:

[(Frida, 11, 3), (Bandit, 12, 6)]

現(xiàn)在我們來看一下獲取單只小狗詳細(xì)信息的操作,為了能夠?qū)崟r地獲取小狗的最新數(shù)據(jù),我們返回 Flow:

@Query("SELECT * FROM Dog WHERE name = :name")
fun getDog(name: String): Flow<Dog>

如果我們調(diào)用 getDog("Frida"),F(xiàn)low 會返回一個對象: (Frida, 11, 3)。

只要是數(shù)據(jù)庫中的任意一個數(shù)據(jù)有更新,無論是哪一行數(shù)據(jù)的更改,那就重新執(zhí)行 query 操作并再次派發(fā) Flow,因此當(dāng)小狗 Frida 有更新時我們會收到最新的數(shù)據(jù)。同樣道理,如果一個不相關(guān)的數(shù)據(jù),比如小狗 Bandit 有更新時我們的 Flow 也會被派發(fā),而且會收到與之前相同的數(shù)據(jù): (Frida, 11, 3)。

這是因?yàn)?SQLite 數(shù)據(jù)庫的內(nèi)容更新通知功能是以表 (Table) 數(shù)據(jù)為單位,而不是以行 (Row) 數(shù)據(jù)為單位,因此只要是表中的數(shù)據(jù)有更新,它就觸發(fā)內(nèi)容更新通知。Room 不知道表中有更新的數(shù)據(jù)是哪一個,因此它會重新觸發(fā) DAO 中定義的 query 操作。您可以使用 Flow 的操作符,比如 distinctUntilChanged 來確保只有在當(dāng)您關(guān)心的數(shù)據(jù)有更新時才會收到通知。

@Dao
abstract class DoggosDao {
    @Query("SELECT * FROM Dog WHERE name = :name")
    abstract fun getDog(name: String): Flow<Dog>
    fun getDogDistinctUntilChanged(name:String) =   
           getDog(name).distinctUntilChanged()
}

推薦您通過 Flow 進(jìn)行可觀察的讀操作,以獲取數(shù)據(jù)庫中數(shù)據(jù)更新的通知!您可以在您的整個應(yīng)用中使用協(xié)程 (Coroutine) 和 Flow,而且還可使用 Jetpack 庫中支持的其他協(xié)程功能,比如: 生命周期感知型協(xié)程范圍 (lifecycle-aware coroutine scopes) 、掛起生命周期感知型協(xié)程 (suspend lifecycle-aware coroutines),也包括 Flow 轉(zhuǎn) LiveData 的操作。

查看更多使用 Flow 的案例,可參考我們之前發(fā)布的一篇基于 Android 開發(fā)者峰會應(yīng)用的最佳實(shí)踐 的文章。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容