RxJava (или Rx.NET), эквивалент RACObserve от ReactiveCocoa

Учитывая произвольное поле в объекте Java, я хочу создать Observable, который будет следить за этим полем и отправлять новый результат в Observer каждый раз, когда значение поля изменяется. В ReactiveCocoa есть макрос RACObserve, который, похоже, делает именно это.

Я хочу знать, как реализовать аналогичную функциональность с помощью RxJava.

Например, скажем, у меня был следующий простой класс:

public class Foo {
    enum State {
        Idle,
        Ready,
        Error
    }

    private State currentState = State.Idle;

    //methods that can change currentState
}

Я хочу создать Observable<State>, который будет передавать новое состояние наблюдателю каждый раз, когда что-то меняет значение currentState.

В ReactiveCocoa, похоже, я бы написал что-то вроде следующего (пожалуйста, извините за мой псевдо-Objective-C):

[RACObserve(self, currentState) subscribeNext:^(NSString *newState) {
    NSLog(@"%@", newState);
}];

Как мне добиться аналогичной функциональности в RxJava? Я думаю, что мне может понадобиться обернуть все изменения в currentState в установщик, но мне не ясно, где я должен затем вызвать Observable.create и как передать изменения currentState в Observer.


person martiansnoop    schedule 18.01.2014    source источник


Ответы (4)


ReactiveCocoa на самом деле больше похож на ReactiveUI (http://www.reactiveui.net), чем на обычный Rx. А в ReactiveUI вы можете использовать this.WhenAnyValue(x => x.PropName), чтобы делать именно то, что вы хотите.

person Todd Berman    schedule 03.03.2014

Недавно я наткнулся на эту же проблему, в итоге я использовал PropertyChangeListener, который будет испускать объект при изменении свойства, см. следующее:

Обновить прослушиватель:

public class GameUpdateListener {

public static Observable<Object> changed(Game game) {
    final BehaviorSubject<Object> subject = BehaviorSubject.create((Object)game);

    game.addPropertyChangeListener(new PropertyChangeListener() {
        @Override
        public void propertyChange(PropertyChangeEvent propertyChangeEvent) {
          subject.onNext( (Object)propertyChangeEvent.getNewValue());
        }
    });
    return subject;
  }
}

Некоторый пользовательский объект:

public class Game {
 private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
...
  public setSomeField(String field){
       this.field = field;
       pcs.firePropertyChange("field", this.field, field);

}

public void addPropertyChangeListener(PropertyChangeListener propertyChangeListener) {
    pcs.addPropertyChangeListener(propertyChangeListener);
}

...

}

Наблюдать:

Game game = new Game();
GameUpdateListener listener = new GameUpdateListener();

final Observable<Object> gameObserver = listener.changed(game);

    gameObserver.subscribe(new Action1<Object>() {
        @Override
        public void call(Object o) {
            Log.e(TAG, "Object Changed");
        }
    });


game.setSomeField("New value");

Это будет работать нормально, если вам не нужно снова создавать экземпляр вашего объекта. Возможно, решение этой проблемы состоит в том, чтобы создать локальный метод установки и внести в него изменения.

person AshleyJ    schedule 09.04.2014

Поскольку заголовок вашего вопроса содержит «или Rx.NET», вот мое предложение (я не знаю о RxJava, вы можете найти что-то подобное).

Вероятно, вам придется использовать какой-то механизм в сеттере. Стандартным способом в .NET является использование интерфейса INotifyPropertyChanged. Затем, запуская события, вы можете создать IObservable<T> из этого потока, используя Observable.FromEvent<TEvent, TArgs>()

Вы можете найти действительно хороший пример того, что вы хотите сделать (.NET) здесь.

(кредиты Rob Foncesa-Ensor)

person cvbarros    schedule 29.01.2014

Я думаю, что вам нужен Subject<T>. Он реализует IObserver<T>, поэтому вы можете вызвать OnNext(T) для запуска нового значения, а также IObservable<T>, которое вы можете опубликовать как общедоступное, чтобы на него можно было подписаться.

Если вам нужно отправить последнее значение новым подписчикам, вы можете использовать ReplaySubject<T> с размером буфера 1.

Вот базовая реализация:

public class SomeService
{
    private Subject<int> values = new Subject<int>();

    public IObservable<T> Values
    {
        get
        {
            // AsObservable prevents it from being cast back to Subject
            return values.AsObservable();
        }
    }

    // Private; called by some internal mechanism
    private void SetValue(int newValue)
    {
        newValue.OnNext(newValue);
    }
}
person Richard Szalay    schedule 03.03.2014