onNext() никогда не вызывается для PublishSubject

Я пытаюсь создать презентатор, который вычисляет некоторые события в течение некоторого периода времени, показывает загрузку только при первой загрузке и обновляет пользовательский интерфейс, когда это делается. Поскольку события могут быть обновлены несколькими способами (например, с помощью пользовательских настроек), мне нужно иметь возможность сообщить докладчику, что события были обновлены и что он должен обновить их снова. Вот что у меня есть прямо сейчас:

                      subject
                            .map<List<UpcomingRowViewModel>> {
                                provider.calculateEventsBetween(TimePeriod.aYearFrom(firstDay))
                            }
                            .doOnSubscribe {
                                view.showLoading()
                            }
                            .observeOn(resultScheduler)
                            .subscribeOn(workScheduler)
                            .subscribe { upcomingRowViewModels ->
                                view.display(upcomingRowViewModels)
                            }
                      subject.onNext(TRIGGER)

Субъект является PublishSubject из Int. Я делаю onNext() сразу после подписки, потому что хочу, чтобы данные обновлялись, как только я подпишусь на них.

Приведенный выше код творит чудеса в моих модульных тестах, а также только тогда, когда я запускаю его на устройстве с подключенным отладчиком. Если я просто запускаю его (без отладчика), он достигает части view.showLoading(), но никогда не достигает части provider.calculateEventsBetween(TimePeriod.aYearFrom(firstDay), поэтому пользовательский интерфейс «зависает» при загрузке.

Любые идеи?


person Alex Styl    schedule 05.08.2017    source источник


Ответы (1)


Вероятной причиной, по которой вы не видите вызываемого потребителя, является .subscribeOn(workScheduler). Применяя это к Subject, что само по себе не имеет практического применения, поскольку при подписке на Subject нет побочных эффектов подписки, вы откладываете подписку на Subject ровно настолько, чтобы вызов onNext не нашел наблюдателей в этот момент. .

Вероятно, вы хотите что-то вроде этого:

subject
    .observeOn(resultScheduler)             // <--------------- (1)
    .doOnNext {
        view.showLoading()
    }
    .observeOn(workScheduler)               // <--------------- (2)
    .map<List<UpcomingRowViewModel>> {
        provider.calculateEventsBetween(
            TimePeriod.aYearFrom(firstDay))
    }
    .observeOn(resultScheduler)             // <--------------- (3)
    .subscribe { upcomingRowViewModels ->
        view.display(upcomingRowViewModels)
    }
subject.onNext(TRIGGER)

Вместо doOnSubscribe, который выполняется один раз, (1) гарантирует, что, когда есть работа, эмиссия onNext субъекта вызовет индикатор загрузки в основном потоке (при условии, что resultScheduler равен AndroidSchedulers.mainThread в нетестах). Затем вы захотите выполнить сопоставление с основным потоком и, таким образом, (2) переместить элемент в фоновый поток. Как только сопоставление произошло, результирующий элемент снова перемещается в основной поток в (3), где ваше представление может его отобразить.

person akarnokd    schedule 05.08.2017
comment
Это сделало трюк! Премного благодарен за ваш ответ. это многое прояснило в моей голове о том, как работает API, потому что я все неправильно понял! - person Alex Styl; 06.08.2017
comment
Я очень ценю ваш ответ, он показывает важность назначения правильного планировщика дляObserverOn() - person Davide; 20.03.2018