【问题标题】:RXAndroid better way to write nested subscriptionsRXAndroid 编写嵌套订阅的更好方法
【发布时间】:2018-10-08 22:29:45
【问题描述】:

我正在使用适用于 Android 的 RXBle 库。为了从 BLE 外围设备(BLE 设备)读取数据,我最终设置了多个订阅,所有订阅都在彼此之间,如下所示:

    Disposable scanSubscription = null;

    public void startScan() {
        scanSubscription = rxBleClient
            .scanBleDevices(settings, filter)
            .take(1)
            .subscribe(
                scanResult -> connectDevice(scanResult.getBleDevice()),
                throwable -> {}
            );
    }

    public void connectDevice(RxBleDevice device) {
        device
            .establishConnection(false)
            .subscribe(
                connection -> requestMtu(connection),
                throwable -> {}
            );
    }

    public void requestMtu(final RxBleConnection connection) {
        connection
            .requestMtu(185)
            .subscribe(
                mtu -> readCharacteristic(connection),
                throwable -> {}
            );
    }

    public void readCharacteristic(final RxBleConnection connection) {
        /* this one eventually scanSubscription.dispose!!!!! */
    }

本质上,我有一系列对事物执行操作的函数,然后订阅生成的 Single(我认为我使用的术语正确)

我的问题是,有什么更好的写法?

更重要的是,我从未取消订阅的嵌套订阅会发生什么?请注意,在第一个函数中,我调用了一个 take(1)...最终我只是处置了调用所有这些的顶级一次性。

【问题讨论】:

    标签: android android-bluetooth rx-android rxandroidble


    【解决方案1】:

    没有。那不是RX方式。我建议给this a quick read

    tl;dr 是您希望将代码布置出来,使其像流一样流动。 Rx 试图解决的一件事是消除嵌套回调。这种“流”方法可以做到这一点。

    现在看看你可以做些什么来让它变得更好。这是重写代码的一种方法,使其成为流而不是一组嵌套回调:

    Disposable scanSubscription = null;
    
    public void doThing() {
        scanSubscription = rxBleClient
            .scanBleDevices(settings, filter)
            .take(1)
            .map(scanResult -> scanResult.establishConnection(false))
            .map(connection -> connection.requestMtu(185))
            .map(mtu -> <do thing>)
            .subscribe(/* do things with final value */)
    }
    

    这是另一种方法:

    Disposable scanSubscription = null;
    
    public void doThing() {
        scanSubscription = rxBleClient
            .scanBleDevices(settings, filter)
            .take(1)
            .flatMap(scanResult -> scanResult.establishConnection(false))
            .flatMap(connection -> connection.requestMtu(185).map(result -> Pair(connection, result)))
            .flatMap(result -> {
                Connection c = result.first;
                Mtu mtu = result.second;
                //do thing
            })
            .subscribe(/* do things with final value */)
    }
    

    【讨论】:

    • @idunnoloz 感谢您的回复。我有点困惑的部分是我如何从代码中你说“做事”的部分访问connection。有什么建议吗? MTU 更改后,我需要从连接中读取数据。
    • @wheresmycookie 根据您想要的“干净”程度,您可以让map() 像这样返回一对:.map(connection -&gt; new Pair(connection, connection.requestMtu(185)))。或者,您可以创建一个结果类,其中包含您想要向下传递的字段并返回它。
    • @wheresmycookie 我更新了我的答案,为您提供另一种解决问题的方法,如果您需要将连接传递到流中。
    • 啊,太好了!这就是我要找的!还有一件事,然后我满足于支持这个解决方案:假设每隔几分钟我想打电话给doThing(),在你的例子中,这将删除当前的订阅并用新版本的自身“替换”它。 (我知道这是一个奇怪的请求,但由于操作系统的限制,我不得不偶尔重置扫描)。在延迟循环中再次调用dispose()doThing() 就足够了吗?
    • @wheresmycookie 这取决于。 dispose() 将为流中运行的所有线程设置中断标志,因此您需要确保您的代码可以正确处理中断和错误。但是假设您确实可以优雅地处理中断,那么是的,您可以这样做。除非您需要确保执行已停止,否则您不需要使用“延迟循环”执行此操作。一旦调用dispose(),您的消费者将停止接收结果。
    猜你喜欢
    • 2019-03-14
    • 1970-01-01
    • 2020-11-25
    • 1970-01-01
    • 1970-01-01
    • 2019-11-16
    • 2019-11-04
    • 1970-01-01
    • 2021-04-27
    相关资源
    最近更新 更多