24

Observable从经典 Java 事件模式创建 Rx-Java 的最佳方法是什么?也就是说,给定

class FooEvent { ... }

interface FooListener {
  void fooHappened(FooEvent arg);
}

class Bar {
  public void addFooListener(FooListener l);
  public void removeFooListener(FooListener l);
}

我要实施

Observable<FooEvent> fooEvents(Bar bar);

我想出的实现是:

Observable<FooEvent> fooEvents(Bar bar) {
  return Observable.create(new OnSubscribeFunc<FooEvent>() {
    public Subscription onSubscribe(Observer<? super FooEvent> obs) {
      FooListener l = new FooListener() {
        public void fooHappened(FooEvent arg) {
          obs.onNext(arg);
        }
      };

      bar.addFooListener(l);

      return new Subscription() {
        public void unsubscribe() {
          bar.removeFooListener(l);
        }
      };
    }
  }); 
}

但是,我真的不喜欢它:

  1. 它非常冗长;

  2. 每个都需要一个监听Observer器(理想情况下,如果没有观察者,则应该没有监听器,否则应该有一个监听器)。这可以通过将观察者计数保持为 中的字段,OnSubscribeFunc在订阅时增加它并在取消订阅时减少来改进。

有更好的解决方案吗?

要求:

  1. 使用现有的事件模式实现而不更改它们(如果我正在控制该代码,我已经可以编写它以返回Observable我需要的)。

  2. 如果/当源 API 更改时出现编译器错误。不能使用Object实际事件参数类型或属性名称字符串来代替。

4

4 回答 4

7

我不认为有一种方法可以为每个可能的事件创建一个通用的 observable,但你当然可以在任何需要的地方使用它们。

RxJava 源代码有一些方便的示例,说明如何从鼠标事件、按钮事件等创建可观察对象。看看这个类,它从 KeyEvents 创建它们:KeyEventSource.java

于 2014-01-30T21:16:39.710 回答
7

你的实现是绝对正确的。

这很冗长

使用 lambdas 会变得不那么冗长(RxJava 2 的示例):

Observable<FooEvent> fooEvents(Bar bar) {
    return Observable.create(emitter -> {
        FooListener listener = event -> emitter.onNext(event);
        bar.addFooListener(listener);
        emitter.setCancellable(() -> bar.removeFooListener(listener));
    }); 
}

理想情况下,如果没有观察者,就应该没有听众,否则只有一个听众

您可以使用share()运算符,使您的 observable hot,即所有订阅者共享一个订阅。它会自动订阅第一个订阅者,并在最后一个订阅者取消订阅时取消订阅:

fooEvents(bar).share()
于 2017-01-26T08:59:42.997 回答
3

我想你可以有同样的汤,如果你使用另一层监听器作为实际回调和你的观察者之间的桥梁,只需重新加热。Actual callback → bridge callback → Observer.

好处:

  • 更线性的代码
  • 实际回调的一个实例,在观察者之外
  • 高阶函数看起来特别好,比如 kotlin 中的函数文字:

Ex(注意创建可观察闭包有多小):

class LocationService @Inject constructor(private val googleApiClient: GoogleApiClient) : ConnectionCallbacks{

    val locationObservable: Observable<Location>    

    private var passToObservable: (Location?) -> Unit = {}

    init {
        locationObservable = Observable.create<Location> { subscription ->
            passToObservable = { location ->
                subscription.onNext(location)
            }
        }.doOnSubscribe {
            googleApiClient.registerConnectionCallbacks(this)
            googleApiClient.connect()
        }.doOnUnsubscribe {
            googleApiClient.unregisterConnectionCallbacks(this)
        }
    }

    override fun onConnected(connectionHint: Bundle?) {
        val location = LocationServices.FusedLocationApi.getLastLocation(googleApiClient)
        passToObservable(location)
    }

    override fun onConnectionSuspended(cause: Int) {
        //...
    }
}
于 2015-11-13T22:48:41.123 回答
-1

如果您想要一些简单且内置的东西,请尝试这种方法http://examples.javacodegeeks.com/core-java/beans/bean-property-change-event-listener/

java.beans.PropertyChangeEvent;
java.beans.PropertyChangeListener;
java.beans.PropertyChangeSupport;

从该站点,有一个片段显示了如何使用它

package com.javacodegeeks.snippets.core;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;

public class BeanPropertyChangeEventListener {

    public static void main(String[] args) throws Exception {

        Bean bean = new Bean();
        bean.addPropertyChangeListener(new MyPropertyChangeListener());

        bean.setProperty1("newProperty1");
        bean.setProperty2(123);


        bean.setProperty1("newnewProperty1");
        bean.setProperty2(234);

    }

    public static class MyPropertyChangeListener implements PropertyChangeListener {
        // This method is called every time the property value is changed
        public void propertyChange(PropertyChangeEvent evt) {
            System.out.println("Name = " + evt.getPropertyName());

  System.out.println("Old Value = " + evt.getOldValue());

  System.out.println("New Value = " + evt.getNewValue());

  System.out.println("**********************************");
        }
    }

    public static class Bean {

        private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

        // Property property1
        private String property1;
        // Property property2
        private int property2;

        public String getProperty1() {
            return property1;
        }
        public void setProperty1(String property1) {
            pcs.firePropertyChange("property1", this.property1, property1);
            this.property1 = property1;
        }

        public int getProperty2() {
            return property2;
        }
        public void setProperty2(int property2) {
            pcs.firePropertyChange("property2", this.property2, property2);
            this.property2 = property2;
        }

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

    }

}

这很简单

于 2014-01-18T01:21:21.270 回答