从普通的Java事件创建Observable

从古典Java事件模式创建Rx-Java Observable的最佳方式是什么? 那就是给定的

 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观察者计数保持为字段来OnSubscribeFunc ,在订阅时递增,在取消订阅时递减。

有更好的解决方案吗?

要求:

  1. 在不改变它们的情况下处理事件模式的现有实现(如果我正在控制这些代码,那么我已经可以编写它来返回我需要的Observable )。

  2. 如果源API发生更改,则会发生编译器错误。 没有使用Object而不是实际的事件参数类型或属性名称字符串。

我不认为有一种方法可以为每个可能的事件创建一个通用观察值,但是您可以在任何需要的地方使用它们。

RxJava源代码提供了一些如何从鼠标事件,按钮事件等创建可观察事件的方便的例子。看看这个类,从KeyEvents创建它们: KeyEventSource.java 。

你的实现是绝对正确的。

这是相当详细的

对lambda表达式的详细说明(例如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()运算符,这使得您可观察到的热点 ,即所有用户共享单个订阅。 它会自动向第一位订阅者订阅,并在最后一位订阅者取消订阅时取消订阅:

 fooEvents(bar).share() 

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

优点:

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

例如(注意创建可观察的闭包有多小):

 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) { //... } } 

如果你想要简单和内置的东西,试试这个方法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); } } } 

这很简单

Interesting Posts