Should I unsubscribe when using rxbinding?

How I use RxBinding with Kotlin:

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) returns a Subscription . Should I store it as a link and unsubscribe onPause() or onDestroy() ?

Like this:

 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() } 
+5
source share
4 answers

I did a little test setup to find out. This is not an Android application, but imitates class relationships. Here's what it looks like:

 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") } 

In this snippet, I create a View instance containing a reference to Context . the view has a callback for click events that I wrap in an Observable . I call the callback once, then I remove all references to View and Context and save the PhantomReference . Then, in a separate thread, I wait until the Context instance is released. As you can see, I never unsubscribe from Observable .

If you run the code, it will print

Click

Assembled

and then complete the verification that the Context reference has indeed been released.


What does this mean for you

As you can see, the Observable will not prevent the collection of objects referenced by the objects if the only links it has for it are circular. You can learn more about circular links in this question .

However, this is not always the case. Depending on the operators you use in the observed chain, the link may leak, for example. by the scheduler, or if you combine it with an infinite observable, such as interval() . Exclusively unsubscribing from an observable is always a good idea, and you can reduce the required template using something like RxLifecycle .

+6
source

I think Jake Wharton (creator of the library) gave a better answer :

Treat a signed RxView.clicks () (or any Observable from this library, for that matter), as you would a View link itself. If you transfer it (or subscribe to it) somewhere outside your lifetime Look, you have just leaked all your activity.

So, if you just subscribe inside your ViewHolder, there is no need to unsubscribe, since there is no need to unregister the click from the listener you did it manually.

+3
source

Yes, if you look in the doc , it explicitly says:

  • A warning. The created observable retains a strong view reference. Unsubscribe to free this link.
+1
source

Yes, you must unsubscribe when using RxBinding .

Here is one way ... (in java, could it be changed for kotlin?)

Collect

As part of your activity or fragment, add disposable objects to CompositeDisposable, which you will use in onDestroy ().

 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); } 

Dispose

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

Source: https://habr.com/ru/post/1262343/


All Articles