Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJava (or Rx.NET) equivalent of ReactiveCocoa's RACObserve

Given an arbitrary field on a Java object, I want to create an Observable that will watch that field and push a new result to an Observer every time the value of the field changes. ReactiveCocoa has a macro called RACObserve, which appears to do exactly this.

I want to know how to implement similar functionality using RxJava.

For example, say I had the following simple class:

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

    private State currentState = State.Idle;

    //methods that can change currentState
}

I want to create an Observable<State> that will push the new state to an Observer every time something changes the value of currentState.

In ReactiveCocoa, it looks like I would write something sort of like the following (please excuse my pseudo Objective-C):

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

How would I achieve similar functionality in RxJava? I'm thinking that I may need to wrap all changes to currentState in a setter, but it's not clear to me where I should then call Observable.create and how to feed the changes of currentState to an Observer.

like image 433
martiansnoop Avatar asked Jan 18 '14 07:01

martiansnoop


2 Answers

ReactiveCocoa is actually more similar to ReactiveUI (http://www.reactiveui.net) than just plain Rx. And in ReactiveUI, you can use this.WhenAnyValue(x => x.PropName) to do exactly what you want.

like image 109
Todd Berman Avatar answered Nov 16 '22 07:11

Todd Berman


I stumbled across this same problem recently, I ended up using PropertyChangeListener, which will emit an object when a property is changed, see the following:

Update Listener:

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;
  }
}

Some custom object:

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);
}

...

}

Observe:

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");

This will work fine as long as you don't need to instantiate your object again. Perhaps a solution to this is to create a local setter method and emit a change there.

like image 22
AshleyJ Avatar answered Nov 16 '22 07:11

AshleyJ