Должен ли я отказаться от подписки при использовании rxbinding?

Существует то, как я использую RxBinding с 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) возвращает Subscription . Должен ли я хранить его как ссылку и onPause() подписку 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") } 

В этом фрагменте я создаю экземпляр представления, содержащего ссылку на Context . Представление имеет обратный вызов для событий кликов, которые я обертываю в Observable . Я запускаю обратный вызов один раз, затем я удаляю все ссылки на View и Context и сохраняю только PhantomReference . Затем, в отдельном потоке, я жду, пока экземпляр Context будет выпущен. Как вы можете видеть, я никогда не отписываюсь от Observable .

Если вы запустите код, он распечатает

Нажмите

собранный

А затем прекратить доказательство того, что ссылка на Context действительно была выпущена.


Что это значит для вас

Как вы можете видеть, Observable не предотвратит сбор объектов, на которые ссылаются объекты, если единственные ссылки, которые у него есть, являются круговыми. Вы можете больше узнать о круговых ссылках в этом вопросе .

Однако это не всегда так. В зависимости от операторов, которые вы используете в наблюдаемой цепочке, ссылка может быть просочилась, например, планировщиком или если вы объедините ее с бесконечным наблюдаемым, например interval() . Исключительно отказ от подписки на наблюдаемые всегда является хорошей идеей, и вы можете уменьшить необходимый шаблон, используя что-то вроде RxLifecycle .

Я думаю, что Джейк Уортон (создатель библиотеки) дал лучший ответ :

Относитесь к подписанному RxView.clicks () (или любому наблюдаемому из этой библиотеки, если на то пошло), как и сама ссылка View. Если вы передадите его (или подпишитесь на него) где-то вне времени существования View, вы просто пропустили всю свою активность.

Поэтому, если вы просто подписываетесь внутри своего ViewHolder, вам не нужно отменять подписку, так как вам не нужно будет отменить регистрацию прослушивателя кликов, если вы делаете это вручную.

Да, если вы посмотрите в документе , он прямо говорит:

  • Предупреждение: созданный наблюдаемый сохраняет сильную ссылку на view . Отказаться от подписки, чтобы освободить эту ссылку.

Да, вы должны отказаться от подписки при использовании RxBinding .

Вот один из способов … (в java, может быть изменен для kotlin?)

собирать

В своей деятельности или фрагменте добавьте одноразовые объекты в CompositeDisposable, которые вы будете использовать в 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); } 

избавиться

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