RxJava Observable.cache недействителен

Я пытаюсь изучить rxjava в среде Android. Скажем, у меня есть наблюдаемое, которое испускает результат сетевого вызова. Если я правильно понял, широко распространенный подход к решению изменений конфигурации заключается в следующем:

  • сохранить наблюдаемое в объекте сохраненного фрагмента/одинарного/приложения

  • примените оператор кеш к наблюдаемому

  • подписаться/отписаться в правильных обработчиках жизненного цикла

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

Теперь, мой вопрос:

Есть ли способ заставить наблюдаемое испускать новое значение (и аннулировать кешированный)? Нужно ли создавать новые наблюдаемые каждый раз, когда мне нужны свежие данные из сети (что не похоже на плохую практику в мире Android, потому что это сделает gc дополнительной работой)?

Большое спасибо,

Федерико

Ответ 1

Создайте собственную реализацию OnSubscribe, которая делает то, что вы хотите:

public static class OnSubscribeRefreshingCache<T> implements OnSubscribe<T> {

    private final AtomicBoolean refresh = new AtomicBoolean(true);
    private final Observable<T> source;
    private volatile Observable<T> current;

    public OnSubscribeRefreshingCache(Observable<T> source) {
        this.source = source;
        this.current = source;
    }

    public void reset() {
        refresh.set(true);
    }

    @Override
    public void call(Subscriber<? super T> subscriber) {
        if (refresh.compareAndSet(true, false)) {
            current = source.cache();
        }
        current.unsafeSubscribe(subscriber);
    }

}

Этот бит кода демонстрирует использование и показывает, что кэш по существу является reset:

Observable<Integer> o = Observable.just(1)
        .doOnCompleted(() -> System.out.println("completed"));
OnSubscribeRefreshingCache<Integer> cacher = 
    new OnSubscribeRefreshingCache<Integer>(o);
Observable<Integer> o2 = Observable.create(cacher);
o2.subscribe(System.out::println);
o2.subscribe(System.out::println);
cacher.reset();
o2.subscribe(System.out::println);

Вывод:

completed
1
1
completed
1

Кстати, вы можете заметить, что .cache не истекает до завершения. Это ошибка, которая должна быть исправлена ​​rxjava 1.0.14.

Что касается проблем с давлением в ГК, каждый оператор, применяемый к Observable, создает новый Observable обычно через lift или create. Состояние базового члена, связанное с созданием нового Observable, является ссылкой на функцию OnSubscribe. cache отличается от большинства тем, что он удерживает состояние через подписки, и это имеет потенциал для давления GC, если оно содержит много состояний и часто выбрасывается. Даже если вы использовали одну и ту же измененную структуру данных для хранения состояния при сбросах, GC все равно придется обрабатывать содержимое структуры данных при ее очистке, чтобы вы не могли получить много.

Оператор RxJava cache построен для нескольких параллельных подписок. Вероятно, вы можете себе представить, что функциональность reset может оказаться проблематичной для реализации. Во что бы то ни стало поднимайте вопрос о RxJava github, если хотите продолжить изучение.