带有Kotlin-coroutines的房间观察数据库的变化

Raj*_*eck 9 android kotlin kotlinx.coroutines

因此,我最近开始使用协同程序进行实验,我从Rxjava2切换到协同程序,我还没有掌握它但仍然,我遇到了一个需要观察我的数据库更改并更新对应的UI的情况.

RxJava曾经为我提供Flowables,Completeable等,使用它我可以观察到Db的变化.

    abstract fun insert(data: SomeData): Long

    @Query("SELECT * FROM somedata_table")
    abstract fun getData(): Flowable<List<SomeData>>
Run Code Online (Sandbox Code Playgroud)

所以现在这里我曾经订阅了getData并且总是习惯于观察变化

现在输入coroutines,我使用带有延迟结果的暂停函数来返回我的响应

    @Insert(onConflict = OnConflictStrategy.IGNORE)
    abstract fun insert(data: SomeData): Long

    @Query("SELECT * FROM somedata_table")
    abstract fun getData(): List<SomeData>
Run Code Online (Sandbox Code Playgroud)
suspend fun getAllSomeData():Deferred<List<SomeData>>{
        return GlobalScope.async (context= coroutineContext){
            database.myDao().getData()
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在我无法听取更新,协程中的频道可能是正确的答案吗?但我不确定如何使用Room.

Tra*_*llo 10

使用Room 2.2.0 Flows和kotlin 协程。这是有争议的,但我不喜欢LiveData,因为它在 UI 线程上为您提供结果。如果您必须进行任何数据解析,则必须将所有内容推回另一个 IO 线程。它也比直接使用频道更干净,因为您每次想要收听事件时都必须进行额外的openSubscription().consumeEach { .. }调用。

流程方法需要以下版本:

// 此版本在其非实验版本中使用协程和流程

org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.2
androidx.room:room-runtime:2.2.0
androidx.room:room-compiler:2.2.0
Run Code Online (Sandbox Code Playgroud)

道:

@Dao
interface MyDao {
     @Query("SELECT * FROM somedata_table")
     fun getData(): Flow<List<SomeData>>
}
Run Code Online (Sandbox Code Playgroud)

课堂观察:

launch {
   dao.getData().collect { data ->
    //handle data here
   }
}
Run Code Online (Sandbox Code Playgroud)

如果您的调用类本身不是CoroutineScope,则您必须使用它的上下文来调用 launch。这可以是GlobalScope或您创建的其他一些类。

GlobalScope.launch {
   dao.getData().collect { data ->
    //handle data here
   }
}
Run Code Online (Sandbox Code Playgroud)

在收集拉姆达也将获得每UDPATE表很像的Rx onNext电话。


Dan*_*uks 7

目前,有两种不同的方法可以做到这一点。第一种是使用 liveData 构建器函数。要使其工作,您需要将生命周期更新为androidx.lifecycle:*:2.2.0-alpha01或任何更新的版本。LiveData builder函数将用于异步调用getData(),然后使用emit()发出结果。使用此方法,您将把 Room getData() 函数修改为挂起函数,并将返回类型包装为 LiveData,替换之前使用的 Flowable。

@Query("SELECT * FROM somedata_table")
abstract suspend fun getData(): LiveData<List<SomeData>>
Run Code Online (Sandbox Code Playgroud)

在您的视图模型中,您创建了一个引用您的 Room 数据库的 liveData

val someData: LiveData<SomeData> = liveData {
    val data = database.myDao().getData() 
    emit(data)
}
Run Code Online (Sandbox Code Playgroud)

第二种方法是从我们的数据库中以 Flow 形式获取数据。要使用它,您需要将 Room 更新为androidx.room:room-*:2.2.0-alpha02(当前最新的)或更新的版本。此更新使@Query DAO 方法的返回类型为 Flow 如果查询中的观察表无效,则返回的 Flow 将重新发出一组新值。使用 Channel 返回类型声明 DAO 函数是错误的

@Query("SELECT * FROM somedata_table")
abstract fun getData(): Flow<List<SomeData>?>
Run Code Online (Sandbox Code Playgroud)

返回类型是一个可空列表的流。该列表可以为空,因为当查询未获取数据时 Room 将返回 null。

为了从流中获取数据,我们将collect{ }在 Presenter/ViewModel 中使用终端操作符。最好在 ViewModel 中执行此操作,因为它带有 ViewModelScope。下面给出的解决方案假设我们在 ViewModel 中执行此操作,其中我们提供了 viewModelScope。

    fun loadData(){
        viewModelScope.launch {
            database.myDao()
               .getData()
               .distinctUntilChanged().
               .collect{
                        it?.let{ /** Update your obsevable data here **/
               }
    }
Run Code Online (Sandbox Code Playgroud)