13

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()
}
4

4 に答える 4

13

私はそれを見つけるために小さなテストセットアップを作成しました。これは 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では、 への参照を保持するをインスタンス化しますContext。ビューには、 でラップするクリック イベントのコールバックがありますObservable。コールバックを 1 回トリガーしてから、 および へのすべての参照を無効にしViewContextのみを保持しPhantomReferenceます。次に、別のスレッドで、Contextインスタンスが解放されるまで待ちます。ご覧のとおり、私はObservable.

コードを実行すると、印刷されます

クリック

集めました

そして、 への参照Contextが実際に解放されたことを証明して終了します。


これがあなたにとって何を意味するか

ご覧のとおり、 は、Observableそれへの参照が循環のみである場合、参照されたオブジェクトの収集を妨げません。循環参照の詳細については、この質問を参照してください。

ただし、常にそうであるとは限りません。オブザーバブル チェーンで使用する演算子によっては、参照漏洩する可能性があります。たとえば、スケジューラによって、またはinterval(). オブザーバブルから明示的にサブスクライブを解除することは常に良い考えであり、RxLifecycleのようなものを使用して必要なボイラープレートを減らすことができます。

于 2017-01-05T15:23:46.190 に答える
5

はい、RxBinding を使用する場合は登録を解除する必要があります。

これが1つの方法です...(Javaでは、kotlin用に調整できますか?)

収集

アクティビティまたはフラグメント内で、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();
}
于 2017-05-06T18:38:31.593 に答える
4

はい、 docを見ると、明示的に次のように書かれています。

  • 警告:作成されたオブザーバブルは への強い参照を保持しviewます。この参照を解放するには、購読を解除してください。
于 2017-01-05T10:17:56.370 に答える