在方向更改时在 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()
}
...
}
问题:当我尝试在 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()
}
...
}