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

时间:2019-01-15 18:19:05

标签: android rx-java2 mvp android-orientation android-mvp

The problem: When I trying to rotate phone immediatelly after PullToRefresh, my Observable will not finish it's work because of dispose() method I calling in onPause. I understand why it's happening but I don't have any idea how to dispose without result loss. If I dont call dispose, everything works great but I want to dispose my Disposable correctly to have no problems with memory leaks and etc.

My base presenter:

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

My base use case:

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

In View:

...

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

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

This is Observable code in presenter (handling some network response):

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

If I don't call this, everything (of course) works as expected:

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

1 个答案:

答案 0 :(得分:1)

最后找到了解决方案。现在,仅在按下后退按钮时才处理Disposable,而不要在未绑定的视图中进行处理。因此,我向基本演示者添加了方法:

...

/**
 * 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
    }

    ...
}

最后,在活动中重写onBackPressed()方法:

class MainActivity : AppCompatActivity() {

    ...

    var currentBackPressListener: OnBackButtonClickListener? = null

    ...

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

    ...
}