【问题标题】:Create Observable with dispose handler rxjava使用 dispose 处理程序 rxjava 创建 Observable
【发布时间】:2019-01-04 19:48:11
【问题描述】:

我们想观察视图大小的变化,我们创建一个这样的扩展:

fun View.layoutSizeObservable(): io.reactivex.Observable<Size> {
    return io.reactivex.Observable.create<Size> { emitter ->
        viewTreeObserver.addOnGlobalLayoutListener {
            Log.d("MainFragment", "ViewTreeObserver Listener called back.")
            if (measuredWidth > 0 && measuredHeight > 0) {
                emitter.onNext(Size(measuredWidth, measuredHeight))
            }
        }
    }
}

然后我们像这样使用它,它在功能上运行良好:

sizeChangedDisposable = titleTextView.layoutSizeObservable().subscribe { size: Size ->
    Log.d("MainFragment", "Size changed subscribe on $size")
}

然而,我们不想要的一件事是Listener 是通过addOnGlobalLayoutListener 添加的,但从未删除。

我们可以拨打sizeChangedDisposable.dispose(),它会正确停止订阅:

D/MainFragment:在 $size 上更改订阅大小

但这将继续被调用:

D/MainFragment:ViewTreeObserver 监听器回调。

我们如何以及在哪里删除布局侦听器回调?

【问题讨论】:

    标签: android kotlin rx-java2


    【解决方案1】:

    Disposable 被释放时,你需要移除监听器。为了能够做到这一点,请将Cancellable 操作设置为发射器移除听者。

    示例

    fun View.layoutSizeObservable(): io.reactivex.Observable<Size> {
        return io.reactivex.Observable.create<Size> { emitter ->
            val listener = ViewTreeObserver.OnGlobalLayoutListener {
                Log.d("MainFragment", "ViewTreeObserver Listener called back.")
                if (measuredWidth > 0 && measuredHeight > 0) {
                    emitter.onNext(Size(measuredWidth, measuredHeight))
                }
            }
    
            viewTreeObserver.addOnGlobalLayoutListener(listener)
    
            emitter.setCancellable {
                Log.d("MainFragment", "ViewTreeObserver Listener removed.")
                viewTreeObserver.removeOnGlobalLayoutListener(listener)
            }
        }
    }
    

    顺便说一句,RxBinding 库已经有一个 Observable 用于 global layout listener

    【讨论】:

    • 谢谢!只是一个后续问题:在ObservableEmitter 类中,既有void setCancellable(@Nullable Cancellable c) 又有void setDisposable(@Nullable Disposable d)。是否有理由何时使用一种,何时使用另一种?
    • 没区别,简单点,你也可以emitter.setDisposable(Disposables.fromAction { viewTreeObserver.removeOnGlobalLayoutListener(listener) })
    • 我试过这个,只是注意到它不起作用。 Listener called back 行仍在执行中。我认为这可能是因为监听器被定义为一个 lambda 函数,我们在 addremove 函数上创建了一个不同的 ViewTreeObserver.OnGlobalLayoutListener 实例。但是如果我们把那行改成val listener = ViewTreeObserver.OnGlobalLayoutListener { ... },那么一切都很好。
    • @YuchenZhong 完成
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-07
    • 1970-01-01
    • 2017-01-13
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 2020-11-10
    相关资源
    最近更新 更多