Цепь от текучей до завершаемой с действием

У меня есть SQL-запрос Android Room, который возвращает текучесть:

@Query("SELECT * FROM exercices WHERE lang = 'ru' AND id_exercice = :id")
Flowable<Exercices> getExercicesById(int id);

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

@Override
public Completable setExerciseUsed(int id) {
    return mDatabase.exerciseDao().getExercicesById(id)
            .doOnNext(exercise -> exercise.setIs_used(1))
            .flatMapCompletable(exercise ->
                    Completable.fromAction(() -> mFitnessDatabase.exerciseDao().addExercise(exercise)));
}

Также я пробовал:

Exercices e = mDatabase.exerciseDao().getExercicesById(id).blockingFirst();
    e.setIs_used(0);
    return Completable.fromAction(() -> mDatabase.exerciseDao().addExercise(e));

Но т не работает должным образом. Кажется, что поток испускает много элементов, и после подписки он застрянет в цикле.


person Koroqe    schedule 27.07.2017    source источник


Ответы (2)


Поскольку ваш DAO возвращает Flowable, он будет выдавать свежие данные при каждом изменении таблицы. Таким образом, после вызова mFitnessDatabase.exerciseDao().addExercise(exercise), getExercicesById будет выдавать новые данные, поэтому цепочка будет выполняться вечно.
Если вы хотите, чтобы Room не выдавал данные, просто измените Flowable на Single.
Поскольку вы ожидаете, что будет возвращено одно значение, это хорошая идея ограничить результат одним элементом: "SELECT * FROM exercices WHERE lang = 'ru' AND id_exercice = :id LIMIT 1".

Но на самом деле в вашем случае, если вы хотите изменить параметр элемента, гораздо эффективнее сделать это в рамках одного запроса.
Это может выглядеть так:

@Query("UPDATE exercices SET is_used = 1  WHERE lang = 'ru' AND id_exercice = :id")
fun setIsUsed(id: Int)
person Leo Droidcoder    schedule 16.07.2018

Я не очень разбираюсь в потоках или в том, как отписаться от одного источника с их помощью, но вы думали об использовании LiveData? Вы можете просто добавить источник к объекту LiveData, затем удалить соединение с источником, изменить объект и выполнить свой метод, не зацикливаясь.

Другая идея заключалась бы в том, что вы извлекаете свой объект, сохраняете соединение и обновляете значение вне этого. Поскольку вы сохраняете соединение с базой данных с LiveData, наблюдатель снова выполнит onChanged (поскольку источник = база данных была изменена). Вам нужно только убедиться, что этот метод возвращает, например, null (через setValue) до тех пор, пока база данных не загрузит новое значение объекта.

Если вы хотите остаться с потоковыми объектами, возможно, вам следует подумать о добавлении условия, которое не позволит приложению повторно применить целое число к объекту (и отправить его в базу данных). Имеет ли это смысл для вас?

person Mordag    schedule 27.07.2017