如何使用RxJava将Listener正确转换为Reactive(Observables)?

时间:2016-02-10 13:02:56

标签: java rx-java reactive-programming

我正在使用一款名为AppWarp(http://appwarp.shephertz.com)的多人游戏客户端,您可以在其中添加事件监听器,以便在事件发生时重新调用,让我们回答问题。我们假设我们正在讨论连接侦听器,您需要在其中实现此接口:

public interface ConnectionRequestListener {
    void onConnectDone(ConnectEvent var1);
    void onDisconnectDone(ConnectEvent var1);
    void onInitUDPDone(byte var1);
}

我的目标是主要创建此客户端的Reactive版本,以便在我的应用程序内部使用,而不是直接使用客户端本身(我以后也会依赖于接口,而不仅仅依赖于WarpClient本身在示例中,但这不是重点,请在最后阅读我的问题。)

所以我做的如下:

1)我引入了一个新事件,命名为RxConnectionEvent(主要对连接相关事件进行分组),如下所示:

public class RxConnectionEvent {
    // This is the original connection event from the source client
    private final ConnectEvent connectEvent;
    // this is to identify if it was Connection / Disconnection
    private final int eventType;

    public RxConnectionEvent(ConnectEvent connectEvent, int eventType) {
        this.connectEvent = connectEvent;
        this.eventType = eventType;
    }

    public ConnectEvent getConnectEvent() {
        return connectEvent;
    }

    public int getEventType() {
        return eventType;
    }
}

2)创建了一些事件类型,如下所示:

public class RxEventType {
    // Connection Events
    public final static int CONNECTION_CONNECTED = 20;
    public final static int CONNECTION_DISCONNECTED = 30;
}

3)创建以下observable,它发出新的RxConnectionEvent

import com.shephertz.app42.gaming.multiplayer.client.WarpClient;
import com.shephertz.app42.gaming.multiplayer.client.events.ConnectEvent;
import rx.Observable;
import rx.Subscriber;
import rx.functions.Action0;
import rx.subscriptions.Subscriptions;

public class ConnectionObservable extends BaseObservable<RxConnectionEvent> {

    private ConnectionRequestListener connectionListener;

    // This is going to be called from my ReactiveWarpClient (Factory) Later.
    public static Observable<RxConnectionEvent> createConnectionListener(WarpClient warpClient) {
        return Observable.create(new ConnectionObservable(warpClient));
    }

    private ConnectionObservable(WarpClient warpClient) {
        super(warpClient);
    }

    @Override
    public void call(final Subscriber<? super RxConnectionEvent> subscriber) {
        subscriber.onStart();
        connectionListener = new ConnectionRequestListener() {
            @Override
            public void onConnectDone(ConnectEvent connectEvent) {
                super.onConnectDone(connectEvent);
                callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_CONNECTED));
            }

            @Override
            public void onDisconnectDone(ConnectEvent connectEvent) {
                super.onDisconnectDone(connectEvent);
                callback(new RxConnectionEvent(connectEvent, RxEventType.CONNECTION_DISCONNECTED));
            }

            // not interested in this method (for now)
            @Override
            public void onInitUDPDone(byte var1) { }

            private void callback(RxConnectionEvent rxConnectionEvent)
            {
                if (!subscriber.isUnsubscribed()) {
                    subscriber.onNext(rxConnectionEvent);
                } else {
                    warpClient.removeConnectionRequestListener(connectionListener);
                }
            }
        };

        warpClient.addConnectionRequestListener(connectionListener);
        subscriber.add(Subscriptions.create(new Action0() {
            @Override
            public void call() {
                onUnsubscribed(warpClient);
            }
        }));
    }

    @Override
    protected void onUnsubscribed(WarpClient warpClient) {
        warpClient.removeConnectionRequestListener(connectionListener);
    }
}

4)最后我的BaseObservable如下所示:

public abstract class BaseObservable<T> implements Observable.OnSubscribe<T> {

    protected WarpClient warpClient;

    protected BaseObservable (WarpClient warpClient)
    {
        this.warpClient = warpClient;
    }

    @Override
    public abstract void call(Subscriber<? super T> subscriber);

    protected abstract void onUnsubscribed(WarpClient warpClient);
}

我的问题主要是:我的实现是正确的还是我应该为每个事件创建单独的observable,但如果是这样,这个客户端有超过40-50个事件我是否必须为每个事件创建单独的observable?

我也使用上面的代码如下(在一个简单的&#34;非最终&#34;集成测试中使用它):

public void testConnectDisconnect() {
    connectionSubscription = reactiveWarpClient.createOnConnectObservable(client)
            .subscribe(new Action1<RxConnectionEvent>() {
                @Override
                public void call(RxConnectionEvent rxEvent) {
                    assertEquals(WarpResponseResultCode.SUCCESS, rxEvent.getConnectEvent().getResult());
                    if (rxEvent.getEventType() == RxEventType.CONNECTION_CONNECTED) {
                        connectionStatus = connectionStatus | 0b0001;
                        client.disconnect();
                    } else {
                        connectionStatus = connectionStatus | 0b0010;
                        connectionSubscription.unsubscribe();
                        haltExecution = true;
                    }
                }
            }, new Action1<Throwable>() {
                @Override
                public void call(Throwable throwable) {
                    fail("Unexpected error: " + throwable.getMessage());
                    haltExecution = true;
                }
            });

    client.connectWithUserName("test user");
    waitForSomeTime();
    assertEquals(0b0011, connectionStatus);
    assertEquals(true, connectionSubscription.isUnsubscribed());
}

1 个答案:

答案 0 :(得分:3)

我建议您避免直接扩展BaseObservable,因为它非常容易出错。相反,尝试使用Rx本身为您创建可观察的工具。

最简单的解决方案是使用PublishSubject,它既是Observable又是Subscriber。监听器只需要调用主题的onNext,主题就会发出事件。这是一个简化的工作示例:

public class PublishSubjectWarpperDemo {

    public interface ConnectionRequestListener {
        void onConnectDone();

        void onDisconnectDone();

        void onInitUDPDone();
    }

    public static class RxConnectionEvent {
        private int type;

        public RxConnectionEvent(int type) {
            this.type = type;
        }

        public int getType() {
            return type;
        }

        public String toString() {
            return "Event of Type " + type;
        }
    }

    public static class SimpleCallbackWrapper {
        private final PublishSubject<RxConnectionEvent> subject = PublishSubject.create();

        public ConnectionRequestListener getListener() {
            return new ConnectionRequestListener() {

                @Override
                public void onConnectDone() {
                    subject.onNext(new RxConnectionEvent(1));
                }

                @Override
                public void onDisconnectDone() {
                    subject.onNext(new RxConnectionEvent(2));
                }

                @Override
                public void onInitUDPDone() {
                    subject.onNext(new RxConnectionEvent(3));
                }
            };
        }

        public Observable<RxConnectionEvent> getObservable() {
            return subject;
        }

    }

    public static void main(String[] args) throws IOException {
        SimpleCallbackWrapper myWrapper = new SimpleCallbackWrapper();
        ConnectionRequestListener listner = myWrapper.getListener();// Get the listener and attach it to the game here.
        myWrapper.getObservable().observeOn(Schedulers.newThread()).subscribe(event -> System.out.println(event));

        listner.onConnectDone(); // Call the listener a few times, the observable should print the event
        listner.onDisconnectDone();
        listner.onInitUDPDone();

        System.in.read(); // Wait for enter
    }
}

更复杂的解决方案是使用onSubscribe实现之一来使用Observable.create()创建一个observable。例如AsyncOnSubscibe。此解决方案具有正确处理后备的优势,因此您的事件订阅者不会被事件所淹没。但在你的情况下,这听起来不太可能,因此增加的复杂性可能不值得。