RxJava toMultiMap не работает с базой данных комнаты Запрос - PullRequest
0 голосов
/ 08 января 2019

Я пытаюсь получить карту сообщений с идентификатором ключа автора, подобным этому:

Map<Long, Collection<Message>>

Вот что я пробовал:

messageViewModel.getAll()
                    .flatMap(Flowable::fromIterable)
                    .toMultimap(Message::getAuthorId)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(this::onSuccess);

private void onSuccess(Map<Long, Collection<Message>> longCollectionMap) {
    Collection<Message> messages = longCollectionMap.get(0);
}

Метод messageViewModel.getAll () возвращает:

Flowable<List<Message>>

Итак, я преобразую его в поток Flowable (Flowable :: fromIterable), чтобы он мог испускать по одному элементу за раз вместо всего списка, а затем я сопоставляю с «toMultiMap»

Метод onSuccess никогда не вызывается, я не знаю, что здесь не так. Если я не использую toMultiMap (и делаю соответствующие изменения в коде), он работает, поэтому проблема должна заключаться в методе toMultiMap.

Но когда я попробую это:

List<String> list = Arrays.asList("1", "2", "3");
Flowable.fromIterable(list)
                    .toMultimap(String::length)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(this::onSuccess);

 private void onSuccess(Map<Integer,Collection<String>> integerCollectionMap) {
    Collection<String> strings = integerCollectionMap.get(1);
}

Это работает! Единственное отличие состоит в том, что этот не вызывает базу данных комнаты, чтобы выбрать элементы для повторяемого.

Также в документации сказано:

Обратите внимание, что этот оператор требует, чтобы вышестоящий поток дал сигнал {@code onComplete} для отправки накопленной карты.

Это меня смущает. Так как класс Flowable не имеет метода подписки с onComplete в качестве параметра, и он не используется во втором случае, который я показал выше, все же он работает.

Пожалуйста, помогите мне, это сводит меня с ума.

1 Ответ

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

Я нашел решение для тех, кто проходит через ту же или похожую проблему.

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

Читая больше о RxJava, я понял причину проблемы. Первый звонок:

messageViewModel.getAll()

возвращался

Flowable<List<Message>>

Это означает, что этот источник будет излучать от 0 до n элементов, в данном случае «Списки» сообщения. И действительно, он отправил список сообщений, и после этого было сделано сопоставление. Но он ничего не возвращал, потому что ждал появления «списков» из источника.

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

Таким образом, решение изменяло тип возвращаемого значения messageViewModel.getAll () на:

Single<List<Message>>

Так что теперь он будет выдавать 1 элемент, список сообщений или ошибку. Таким образом, после запуска одного элемента больше не будет, а другие методы в цепочке будут выполняться и возвращать значение.

Однако метод «toMultiMap» не работает с «Single», в классе «Single» такого нет. Таким образом, вы должны преобразовать его в текучий, поэтому я сделал это:

.flatMapPublisher(Flowable::fromIterable)

Итак, в конце код выглядит так:

messageViewModel.getAll() //Returns Single<List<Message>>
                .flatMapPublisher(Flowable::fromIterable) // Creates a flowable from List<Message>
                .toMultimap(Message::getAuthorId)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(this::onSuccess);

Очень хороший и чистый код, требуется некоторое время, чтобы понять, как работает реактивный подход, но оно определенно стоит того. Надеюсь, кто-нибудь найдет это полезным.

...