在方向更改时在 Presenter 中处理 Rx Disposable 的正确方法

The right way to dispose Rx Disposable in presenter on orientation change

问题:当我尝试在 PullToRefresh 之后立即旋转 phone 时,我的 Observable 将无法完成它的工作,因为我在 onPause 中调用了 dispose() 方法。我明白为什么会这样,但我不知道如何在不损失结果的情况下进行处理。 如果我不调用 dispose,一切都很好,但我想正确处理我的 Disposable,以免出现内存泄漏等问题。

我的基地主持人:

abstract class BasePresenter<T> {

    private var view: WeakReference<T>? = null

    /**
     * View reference
     * */
    fun getView(): T? = if (view != null) view!!.get() else null

    /**
     * We should call it in onResume() method in fragment
     * */
    fun bindView(view: T?) {
        if (view != null) {
            this.view = WeakReference(view)
            updateView()
        }
    }

    /**
     * We should call it in onPause() method in fragment
     * */
    fun unbindView() {
        view = null
        dispose()
    }

    protected abstract fun updateView()

    protected abstract fun dispose()
}

我的基本用例:

abstract class UseCase<TResult, in TParam> {

    /**
     * Creates a new instance of [Observable] for specified params
     * @param params Params to create [Observable]
     */
    abstract fun createObservable(params: TParam?): Observable<TResult>

    /**
     * [Observable] which executes UseCase logic for specified params
     * @param params Params to create [Observable]
     */
    fun observable(params: TParam?): Observable<TResult> =
        createObservable(params).doOnError { }

    /**
     * [Observable] with null params
     */
    fun observable() = observable(null)
}

在视图中:

...

override fun onResume() {
    super.onResume()
    presenter.bindView(this@MainFragment)
}

override fun onPause() {
    super.onPause()
    presenter.unbindView()
}
...

这是 Presenter 中的 Observable 代码(处理一些网络响应):

fun update() {
    setRefreshing(true)

    getDataDisposable?.dispose()
    getDataDisposable = getDataUseCase
        .observable(param)
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .switchIfEmpty {
            setRefreshing(false)
        }
        .subscribe { data ->
            [some manipulations with data]
            setRefreshing(false)
        }
}

如果我不调用它,一切(当然)都会按预期工作:

override fun dispose() {
    getDataDisposable?.dispose()
}

终于找到解决办法了。现在我只在按下后退按钮时处理 Disposable,而不是在 view unbouned 上处理它。所以,我向基本演示者添加了方法:

...

/**
 * Method that should be called on back button click in fragment
 * It's planned that all [Disposable] objects will be disposed in implementation of this method
 * */
abstract fun onBackButtonClicked()

...

主持人:

...

override fun onBackButtonClicked() {
    getChartDataDisposable?.dispose()
}

...

查看(片段):

...

override fun onBackButtonClicked() {
    presenter.onBackButtonClicked()
    navigator.back()
}

...

以及拦截点击硬件后退按钮的一些逻辑:

接口:

interface OnBackButtonClickListener {
    fun onBackButtonClicked()
}

碱基片段:

abstract class BaseFragment : Fragment(), OnBackButtonClickListener {

    ...

    override fun onResume() {
        super.onResume()
        (ctx as MainActivity).currentBackPressListener = this@BaseFragment
    }

    override fun onPause() {
        super.onPause()
        (ctx as MainActivity).currentBackPressListener = null
    }

    ...
}

最后,重写了 activity 中的 onBackPressed() 方法:

class MainActivity : AppCompatActivity() {

    ...

    var currentBackPressListener: OnBackButtonClickListener? = null

    ...

    override fun onBackPressed() {
        currentBackPressListener?.onBackButtonClicked()
    }

    ...
}