Как остановить Flowable от выделения большего количества предметов - PullRequest
1 голос
/ 12 января 2020

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

Context

У меня есть Интерактор, который должен закладывать рецепты в БД. Выглядит это так:

    /**
     * This Interactor marks a recipe as "bookmarked" on the DB. The Interactor actually switches
     * the isBookmarked value of the related recipeId. If it was marked as true, it switches its value
     * to false. If it was false, then it switches its value to true.
     */
    class BookmarkRecipeInteractorImpl(
        private val recipesCacheRepository: RecipesCacheRepository
    ) : BookmarkRecipeInteractor {
        override fun execute(recipeId: Int, callback: BookmarkRecipeInteractor.Callback) {
            // Fetches the recipe from DB. The getRecipeById(recipeId) function returns a Flowable.
            // Internally, within the RecipesCacheRepository, I'm using room.
            recipesCacheRepository.getRecipeById(recipeId).flatMap { originalRecipe ->
                // Switches the isBookmarked value
                val updatedRecipe = originalRecipe.copy(
                    isBookmarked = !originalRecipe.isBookmarked
                )
                // Update the DB
                recipesCacheRepository.updateRecipe(updatedRecipe)
                // Here's the issue, since I'm updating a DB record and the getRecipeById returns
                // a Flowable, as soon as I update the DB, the getRecipeById is going to get triggered
                // again, and switch the value again, and again, and again...
            }
            .subscribe(
                {
                    callback.onSuccessfullyBookmarkedRecipe(it.response)
                },
                {
                    callback.onErrorFetchingRecipes()
                }
            )
        }
    }

Итак, если вы следуете коду, ошибка довольно проста. Я застрял на oop, где постоянно меняю запись рецепта.

Возможные решения

1) Включены две разные функции мой DAO, один с именем getRecipeByIdFlowable(id), который возвращает Flowable, а другой с именем getRecipeByIdSingle(id), который возвращает rx.Single. Таким образом, я могу выставить getRecipeByIdSingle(id) через репозиторий и использовать его вместо функции, которая возвращает Flowable. Таким образом я обрезал l oop.

Pro: Это работает.

Con: Мне не нравится, когда такие функции есть в моем DAO.

2) Сохраните Disposable для свойства lateinit и утилизируйте его, как только подписчик вызовет onNext().

Pro: Это работает.

Con: Мне не нравится делать что-то подобное, я чувствую себя хакером.

3) Использование ...getRecipeById(recipeId).take(1).flatMap..., поэтому он обрабатывает только первый испущенный объект.

Pro: Работает, выглядит аккуратно.

Con: Я не уверен, есть ли лучший способ сделать это.

Вопрос

В идеале я хотел бы вызвать какую-то функцию, которая просто позволяет мне отключить поведение Flowable и не дать ему испускать больше элементов при изменении БД. Пока что решение, которое мне нравится больше всего, это # ​​3, но я не совсем уверен, что это правильный способ сделать это.

Спасибо!

Редактировать 1

Я просто добавляю немного больше информации о сценарии использования здесь. Мне нужен Interactor, который при recipeId изменяет значение isBookmarked на БД на его противоположное.

Записи БД выглядят следующим образом:

    data class DbRecipeDto(
        @PrimaryKey
        val id: Int,
        val name: String,
        val ingredients: List<String>,
        val isBookmarked: Boolean = false
    )

Я знаю, что, может быть, есть и другие способы, которыми я мог бы решить эту проблему по-другому. Возможно, я мог бы передать аргумент recipeId arg и аргумент закладки (Boolean) и просто выполнить запрос на обновление.

Но в этом случае использования он полностью составлен, просто пример ; То, что я пытаюсь выяснить , как запретить Flowable испускать больше элементов, если что-то изменится в DB .

1 Ответ

1 голос
/ 15 января 2020

Вам, вероятно, следует позвонить .take(1).singleOrError() в конце getRecipeById(recipeId).

. Это позволит взять первый элемент (или ошибку), выданный Flowable, полученный при вызове getRecipeById, и обернуть его. в Single. По моему мнению, это правильно соответствует семантике того, чего вы хотите достичь.

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

...