Как узнать, было ли наблюдаемое излучение кэшированным значением BehaviourSubject?

я использую BehaviourRelay в качестве наблюдаемого источника, мне нравится, что он выдает последнее кешированное значение при подписке, поэтому мне не нужно вручную вызывать showPlayingState(mPlayStateManager.getCurrentState()).

Однако это создает проблему, когда я хочу отреагировать анимацией при подписке, поскольку я не хочу запускать анимацию при этом кэшированном излучении, которое генерируется при подписке в onCreate, пользовательский интерфейс должен просто перейти в состояние, а не анимировать его. Анимация должна запускаться только в случае "свежего" выброса

Это довольно распространенный вариант использования, по крайней мере, для меня, но мне трудно понять это в rx.

class Activity {

   PlayStateManager mPlayStateManager;
   Button mButton;

   void onCreate(SavedinstanceState state) {
      mPlayStateManager.playState()
        .subscribe(state -> {
           switch(state) {
            case PlayState.PLAYING:
                showPlayingState(true, ???);
                break;
            case PlayState.PAUSED:
                showPlayingState(false, ???);
                break;
           }
        }
   }

   void showPlayingState(boolean isPlay, boolean animate) {
     if(!animate) {
         mButton.setText(isPlay ? "Playing" : "Paused");
     } else {
         mButton.animate()
           .rotate(360)
           .onAnimationEnd(() -> {
              mButton.setText(isPlay ? "Playing" : "Paused");
           })
      }
   }
}


class PlayStateManager {

    BehaviourRelay<PlayState> mSubject = new BehaviourRelay();

    public void set(PlayState state) {
       mSubject.accept(state);
    }

    public Observable<PlayState> playState() {
        return mSubject.hide();
    }
}

person urSus    schedule 20.10.2017    source источник


Ответы (1)


Если я правильно понимаю ваш вопрос, вы не хотите выполнять анимацию, если playState() является более старой информацией, но только тогда, когда она переключает состояние. Другими словами, при первоначальном вызове onCreate() вы не хотите выполнять анимацию, но хотите сделать анимацию, если значение изменится.

enum PlayStateExpanded {
  UNKNOWN,
  PLAYING,
  PAUSED
}

class PlayStateManager {

    BehaviourRelay<PlayStateExpanded> mSubject = 
       new BehaviourRelay(PlayStateExpanded.UNKNOWN);

    public void set(PlayState state) {
       mSubject.accept(
           state == PlayState.PLAYING ? PlayStateExpanded.PLAYING
                                      : PlayStateExpanded.PAUSED);
    }

    public Observable<PlayStateExpanded> playState() {
        return mSubject.hide();
    }
}

void onCreate(SavedinstanceState state) {
  AtomicBoolean firstTime = new AtomicBoolean(true); // note first time
  mPlayStateManager.playState()
    .subscribe(state -> {
       switch(state) {
        case PlayStateExpanded.PLAYING:
            showPlayingState(true, firstTime.get());
            break;
        case PlayStateExpanded.PAUSED:
            showPlayingState(true, firstTime.get());
            break;
       }
       firstTime.set(false); // no longer first time
    }
}

Путем переопределения состояния воспроизведения со значением UNKNOWN условие запуска упрощается. Просто добавив флаг для первого перехода, который сбрасывается после первого использования, вы достигнете поставленной цели.

person Bob Dalgleish    schedule 20.10.2017
comment
да, но тема может начинаться пустой, без кэшированного значения - person urSus; 21.10.2017
comment
А также? Ваш вопрос не описывает поведение в таком случае. Код показал, что вы ждали определения значения. - person Bob Dalgleish; 21.10.2017
comment
что ты имеешь в виду? behaviorrelay не имеет начального значения по умолчанию, поэтому может быть пустым, поэтому при подписке не будет кешированной эмиссии, а первая новая эмиссия будет обработана неправильно как таковая. Кстати, это зависит от того факта, что это реле поведения, о котором вы не должны знать, отсюда и скрытие (), возможно, есть ли способ закодировать его в испускаемых данных? - person urSus; 21.10.2017
comment
Давайте немного вернемся к дизайну. Почему наблюдаемое playState() не определено, пока оно не установлено? Вероятно, его всегда следует определять, возможно, с UNKNOWN в качестве его начального состояния. - person Bob Dalgleish; 22.10.2017
comment
хорошо, это сработает. но мне все равно не нравится то, что надо знать его поведение - person urSus; 22.10.2017
comment
Вам не обязательно знать его поведение. Вы должны предоставить наблюдаемую, которая всегда имеет определенное состояние. Есть разница. - person Bob Dalgleish; 23.10.2017
comment
да, это хорошо, я имею в виду, что первая эмиссия со специальной обработкой в ​​подписчике, возможно, также должна исходить из потока, что эта эмиссия требует такой обработки - person urSus; 23.10.2017
comment
Я согласен. Иногда мы не всегда получаем хорошие данные, которых заслуживаем, и приходится корректировать :) - person Bob Dalgleish; 23.10.2017
comment
Как бы я это сделал? Создание подкласса BehaviorStream для генерации Pair‹Boolean, T› ? - person urSus; 23.10.2017
comment
Позвольте мне переписать мой ответ. - person Bob Dalgleish; 23.10.2017