我应该在使用rxbinding时取消订阅吗?

有我如何使用Kotlin使用RxBinding:

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) reset_password_text_view.clicks().subscribe { presenter.showConfirmSecretQuestionBeforeResetPassword() } password_edit_text.textChanges().skip(1).subscribe { presenter.onPasswordChanged(it.toString()) } password_edit_text.editorActionEvents().subscribe { presenter.done(password_edit_text.text.toString()) } } 

Observable.subscribe(action)返回Subscription 。 我应该保留它作为参考和取消订阅onPause()onDestroy()

喜欢这个:

 private lateinit var resetPasswordClicksSubs: Subscription override fun onViewCreated(view: View?, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) resetPasswordClicksSubs = reset_password_text_view.clicks().subscribe { presenter.showConfirmSecretQuestionBeforeResetPassword() } } override fun onDestroy() { super.onDestroy() resetPasswordClicksSubs.unsubscribe() } 

我已经做了一个小测试设置来找出它。 这不是一个Android应用程序,但它模拟了类的关系。 以下是它的样子:

 class Context class View(val context: Context) { lateinit var listener: () -> Unit fun onClick() = listener.invoke() } fun View.clicks() = Observable.fromEmitter<String>({ emitter -> listener = { emitter.onNext("Click") } }, Emitter.BackpressureMode.DROP) var ref: PhantomReference<Context>? = null fun main(args: Array<String>) { var c: Context? = Context() var view: View? = View(c!!) view!!.clicks().subscribe(::println) view.onClick() view = null val queue = ReferenceQueue<Context>() ref = PhantomReference(c, queue) c = null val t = thread { while (queue.remove(1000) == null) System.gc() } t.join() println("Collected") } 

在这个片段中,我实例化一个View ,该View持有对Context的引用。 这个视图有一个回调我在一个Observable包装的点击事件。 我触发回调一次,然后我把ViewContext所有引用PhantomReference ,只保留一个PhantomReference 。 然后,在一个单独的线程上,我等待Context实例被释放。 正如你所看到的,我从不退订Observable

如果你运行的代码,它会打印

点击

然后终止证明引用Context确实被释放。


这对你意味着什么

正如你所看到的,一个Observable不会阻止被引用的对象被收集,如果只有它的引用是循环的。 你可以在这个问题上阅读更多关于循环引用

然而情况并非总是如此。 根据您在可观察链中使用的运算符,引用可能会被泄漏,例如通过调度程序,或者将它与无限可观察值(如interval()合并。 明确地从一个observable退订总是一个好主意,你可以通过使用像RxLifecycle这样的东西来减少必要的样板。

我认为杰克·沃顿(图书馆的创始人)给出了最好的答案 :

对待订阅的RxView.clicks()(或者这个库中的任何Observable)就像你自己的View引用一样。 如果您在视图的整个生命周期之外的某个地方通过(或订阅),那么您已经泄露了整个活动。

所以,如果你只是在你的ViewHolder中订阅,那么就不需要取消订阅,就像你手动执行的那样,不需要注销一个点击监听器。

是的,如果你看文档 ,它明确地说:

  • 警告:创建的observable保持强烈的view 。 取消订阅释放此参考。

是的,您应该在使用RxBinding时取消订阅 。

这里有一个方法…(在Java中,可以调整kotlin?)

搜集

在Activity或Fragment中,将一次性元素添加到您将在onDestroy()上处理的CompositeDisposable中。

 CompositeDisposable mCompD; // collector Disposable d = RxView.clicks(mButton).subscribe(new Consumer...); addToDisposables(mCompD, d); // add to collector public static void addToDisposables(CompositeDisposable compDisp, Disposable d) { if (compDisp == null) { compDisp = new CompositeDisposable(); } compDisp.add(d); } 

部署

 @Override protected void onDestroy() { mCompD.dispose(); super.onDestroy(); }