RxJava/Android отслеживает прогресс нескольких подписчиков, запущенных в разное время

Я ищу способ, надеюсь, используя RxJava для согласованности, для отслеживания прогресса нескольких подписчиков, которые могут быть запущены в разное время. Я знаю, как объединять подписчиков или подписчиков flatMap вместе, когда все они увольняются из одного метода, но я не знаю, как это сделать, когда они увольняются в разное время из разных методов.

Например, если у меня есть 2 длительные задачи, привязанные к нажатиям кнопок. Я нажимаю кнопку 1 и запускаю наблюдаемый/подписчик, в середине работы я нажимаю кнопку 2, чтобы запустить второй наблюдаемый/подписчик.

Я хочу включить кнопку, когда ни одна задача не запущена, и отключить ее, когда выполняется одна или несколько задач.

Это возможно? Я также стараюсь не устанавливать флаги переменных экземпляра.


person Ben Trengrove    schedule 04.02.2016    source источник
comment
в вашем примере вы должны начать с подписки на обе ваши кнопки в одном и том же месте и, возможно, использовать что-то вроде combineLatest, чтобы получить от них событие   -  person njzk2    schedule 05.02.2016


Ответы (2)


Я бы использовал отдельные BehaviorSubject и scan для отслеживания статуса выполнения. Это очень похоже на переменную экземпляра, но, возможно, это может вдохновить вас на лучшее решение. Что-то вроде этого:

private final BehaviorSubject<Integer> mProgressSubject = BehaviorSubject.create(0);

public  Observable<String> firstLongRunningOperations() {
    return Observable.just("First")
            .doOnSubscribe(() -> mProgressSubject.onNext(1))
            .finallyDo(() -> mProgressSubject.onNext(-1)));
}

public  Observable<String> secondLongRunningOperations() {
    return Observable.just("Second")
            .doOnSubscribe(() -> mProgressSubject.onNext(1))
            .finallyDo(() -> mProgressSubject.onNext(-1));
}

public Observable<Boolean> isOperationInProgress() {
    return mProgressSubject.asObservable()
            .scan((sum, item) -> sum + item)
            .map(sum -> sum > 0);
}

Использование будет таким:

isOperationInProgress()
        .subscribe(inProgress -> {
            if (inProgress) {
                //disable controls
            } else {
                //enable controls
            }
        });

При таком подходе у вас может быть любое количество длительных операций, и вам не нужно запускать их все. Только не забудьте позвонить doOnSubscribe и finallyDo.

PS. Извините, не проверял, но должно работать.

person MyDogTom    schedule 07.02.2016
comment
Обернул реализацию в свой класс, и все заработало. Спасибо! - person Ben Trengrove; 08.02.2016
comment
Что такое BehaviorSubject? - person Dyno Cris; 04.06.2019

Чтобы сделать это возможным, пусть обе длительные операции генерируют событие onNext для PublishSubject. Объедините обе темы с помощью функции zip или CombineLatest и подпишитесь на это. Как только функция объединения получает событие, это означает, что оба субъекта сгенерировали событие onNext, поэтому обе длительные операции завершены, и вы можете включить 3-ю кнопку.

private PublishSubject<Boolean> firstSubject = PublishSubject.create();
private PublishSubject<Boolean> secondSubject = PublishSubject.create();

@Override
public void onStart() {
    super.onStart();
    subscribeToResult();
}

private Observable<Integer> firstOperation() { 
    return Observable.just(100)
                .delay(1000) // takes a while
                .subscribe(tick -> firstSubject.onNext(true));
}

private Observable<Integer> firstOperation() { 
    return Observable.just(200)
                .delay(1000) // takes a while
                .subscribe(tick -> secondSubject.onNext(true));
}

private void subscribeToResult() {
    Observable.zip(
        firstSubject,
        secondSubject,
        (firstResult, secondResult) -> return true
    ).subscribe(
        tick -> thirdButton.setEnabled(true)
    )
}

Обязательно взгляните на функции комбайна RxJava.

person Mauin    schedule 07.02.2016
comment
Мне нравится идея. Будет ли это работать, если вторая кнопка никогда не будет нажата? - person Ben Trengrove; 07.02.2016
comment
zip будет выдавать только в том случае, если все вложенные Observable выдали элемент, combLatest также выдаст последнее значение всех Observable только после того, как каждый наблюдаемый выдал хотя бы одно значение. Таким образом, в вашем случае третья кнопка будет включена только после завершения обеих длительных операций. - person Mauin; 07.02.2016
comment
Мне нужно обработать случай, когда кнопка 2 никогда не нажимается. В основном я хочу, чтобы кнопка была включена, когда никакие задачи не выполняются, и отключена, когда задачи выполняются. Я должен был уточнить это в своем первоначальном вопросе, сейчас отредактирую. - person Ben Trengrove; 08.02.2016