Комната с Kotlin-сопрограмм наблюдать изменения в БД - PullRequest
0 голосов
/ 31 января 2019

Итак, я недавно начал экспериментировать с сопрограммами, я переключился с Rxjava2 на сопрограммы, я еще не понял этого, но все же я столкнулся с состоянием, в котором мне нужно было наблюдать за изменением базы данных и обновлять соответствующий пользовательский интерфейс.к этому.

RxJava раньше предоставлял мне Flowables, Completeable и т. д., используя которые я мог бы наблюдать изменения в Db.

    abstract fun insert(data: SomeData): Long

    @Query("SELECT * FROM somedata_table")
    abstract fun getData(): Flowable<List<SomeData>>

Так вот теперь я использовал подписку на getDataи всегда использовался для наблюдения за изменениями

Теперь введите сопрограммы, я использую приостановленную функцию с отложенным результатом для возврата моих ответов

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

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

Теперь у меня нет возможности прослушиватьобновления, Каналы в сопрограммах может быть правильным ответом?но я не уверен, как использовать его с комнатой.

Ответы [ 3 ]

0 голосов
/ 05 февраля 2019

Зависимости Gradle:

dependencies {
    compile group: 'org.jetbrains.kotlinx', name: 'kotlinx-coroutines-reactive', version: '1.1.1'
}

Комната Дао

@Dao
interface HistoryDao : BaseDao<HistoryEntity> {

    @Query("select * from History order by time desc")
    fun observe(): Flowable<List<HistoryEntity>>

    ...
}

Интерактор ( browserHistoryInteractor ниже) (слой между dao и Fragment / Presenter)

// To get channel of List<HistoryEntity>:
import kotlinx.coroutines.reactive.openSubscription

fun observe() = historyDao.observe().openSubscription() // convert list to Coroutines channel

Presenter / Fragment / Activity (конечная точка (в моем случае это ведущий с учетом жизненного цикла))

import kotlinx.coroutines.Job
import kotlinx.coroutines.launch

private val compositeJob = Job() // somewhat equivalent "compositeDisposable" in rx

override fun onCreate() {
    super.onCreate()

    launch(compositeJob) { // start coroutine
        val channel = browserHistoryInteractor.observe() 
        for (items in channel) {  // waits for next list of items (suspended)
            showInView { view?.setItems(items) }
        }
    }
}

override fun onDestroy() {
    compositeJob.cancel() // as in rx you need to cancel all jobs
    super.onDestroy()
}

https://www.youtube.com/watch?v=lh2Vqt4DpHU&list=PLdb5m83JnoaBqMWF-qqhZY_01SNEhG5Qs&index=5 в 29: 25

0 голосов
/ 15 августа 2019

В настоящее время есть два разных способа сделать это.Первый заключается в использовании функции построителя liveData.Чтобы это работало, вам нужно обновить жизненный цикл до androidx.lifecycle:*:2.2.0-alpha01 или более новой версии.Функция построителя LiveData будет использоваться для асинхронного вызова getData (), а затем использовать emit () для выдачи результата.Используя этот метод, вы измените функцию Room getData () на функцию приостановки и сделаете возвращаемый тип обернутым как LiveData, заменив использовавшийся ранее Flowable.

@Query("SELECT * FROM somedata_table")
abstract suspend fun getData(): LiveData<List<SomeData>>

В вашей модели представления вы создаете liveData, которыйссылается на вашу базу данных Room

val someData: LiveData<SomeData> = liveData {
    val data = database.myDao().getData() 
    emit(data)
}

Второй подход заключается в получении данных из нашей БД как Flow.Чтобы использовать это, вам нужно обновить Room до androidx.room:room-*:2.2.0-alpha02 (на данный момент самая последняя версия) или более новую версию.Это обновление позволяет методам @Query DAO иметь возвращаемый тип Flow. Возвращенный Flow повторно отправит новый набор значений, если таблицы наблюдения в запросе будут признаны недействительными.Объявление функции DAO с типом возвращаемого канала является ошибкой, вместо этого Room рекомендует вам использовать Flow, а затем использовать соседние функции для преобразования потока в канал.

@Query("SELECT * FROM somedata_table")
abstract suspend fun getData(): Flow<List<SomeData>>

Для извлечения и обновления данных мыпреобразует поток полученных холодных данных в горячий канал в нашей Presenter / ViewModel.Лучше сделать это в ViewModel из компонентов архитектуры Android.Приведенное ниже решение предполагает, что мы делаем это в ViewModel, где у нас есть предоставляемая viewModelScope.

fun loadData(){
    val channel = database.myDao().getData().distinctUntilChanged().produceIn(viewModelScope)
    viewModelScope.launch {
        for(i in channel){
            withContext(Dispatchers.Main){ /** Update your obsevable data type with i **/ }
        }
    }

}
0 голосов
/ 31 января 2019

ОРИГИНАЛ:

Вы должны использовать LiveData вместо RxJava (Flowable, Single и т. Д. -> LiveData).В контексте вашего использования RxJava, который обновляет пользовательский интерфейс, соответствующий изменениям в Room DB, LiveData сделает для вас ту же работу, только если он создан Google и специально разработан как альтернатива.на внешние библиотеки.Он входит в состав архитектурных компонентов * стека 1015 *, аналогично Room .

Для получения инструкций по использованию с Room читайте здесь и здесь .

Когда дело доходит до интеграции сопрограмм с комнатой , кажется, что на данный момент нетГотовое решение предоставило , а оно работает на .Возможно, вы могли бы использовать эту статью .

ОБНОВЛЕНИЕ:

По состоянию на Номер 2,1 (Альфа) * ​​1047 * поддержка Kotlin сопрограмм добавлено.Некоторые подробности о том, как его использовать, можно найти в этой статье .

Примечание: Каналы еще не поддерживаются в Room, поскольку это все еще экспериментальная функция.

Удачи:)

...