我应该在使用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
包装的点击事件。 我触发回调一次,然后我把View
和Context
所有引用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(); }