0.前言
使用Rxjava的人越来越多,rxjava现在已经更新到rxjava3了,因其简洁效率高的特点备受程序猿喜爱。然而由rxjava处理不但引起的内存泄漏问题也不得不让人头疼,每次使用完都要手动取消掉订阅也很麻烦而且不一定执行。为了解决这个问题,由此诞生了rxlifecycle,使用rxlifecycle可以跟踪lifeOwnner的生命周期从而自动取消订阅,但是却有许多限制和问题,详情见 为什么不使用 RxLifecycle?,作者已经在文章里面说了。文章最后还亲自推荐使用AutoDisposable,连他本人都认为rxlifecycle不如AutoDisposable了。网上关于AutoDisposable和LiveData相关使用的文章有很多,但是却找不到LiveData结合AutoDisposable一起使用的文章,着实让人费解。很明显,liveData使得代码仅仅在Activity处于活动状态下执行,如果代码使用了Rxjava订阅处理数据(在网略请求中很常见,网略请求经常使用Retrofit+okhttp+Rxjava,详情见笔者另一篇文章 使用Kotlin+Rretrofit+rxjava+设计模式+MVP封装网络请求),这个时候如果不及时取消订阅,则会引起内存泄漏
1.导入
// ViewModel and LiveData
implementation "android.arch.lifecycle:extensions:1.1.1"
// alternatively, just ViewModel
implementation "android.arch.lifecycle:viewmodel:1.1.1"
// alternatively, just LiveData
implementation "android.arch.lifecycle:livedata:1.1.1"
//autodispose
implementation 'com.uber.autodispose:autodispose-android-archcomponents:1.0.0-RC2'
implementation 'com.uber.autodispose:autodispose:1.0.0-RC2'
2.使用
这里举个栗子:
- ViewModel
package foolish
import android.arch.lifecycle.LifecycleOwner
import android.arch.lifecycle.MutableLiveData
import android.arch.lifecycle.Observer
import android.arch.lifecycle.ViewModel
import beans.response.TaskBean
import com.uber.autodispose.AutoDispose
import com.uber.autodispose.android.lifecycle.AndroidLifecycleScopeProvider
import comment.LogUit
import io.reactivex.Observable
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.observers.DisposableObserver
import io.reactivex.schedulers.Schedulers
//TestModel作为MVP或MVVM中的Present,专门负责处理数据
class TestModel:ViewModel(){
val taskLiveData= MutableLiveData<Observable<TaskBean>>()//ViewModel内部持有LiveData
fun initData( lifecycleOwner: LifecycleOwner){
//此处选择在TestModel内部处理LiveData(网上教程很多是把LiveData放在View中处理)
taskLiveData.observe(lifecycleOwner,object : Observer<Observable<TaskBean>>{
override fun onChanged(observable: Observable<TaskBean>?) {
observable!!.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.`as`(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner)))//使用AutoDispose绑定lifecycleOwner,自动取消订阅
.subscribe(object : DisposableObserver<TaskBean>() {
override fun onComplete() {
}
override fun onNext(t: TaskBean) {
LogUit.printI("TaskPresentPrint", "t=${t.toString()}")
}
override fun onError(e: Throwable) {
//处理网略错误
}
})
}
})
}
}
//网略请求获取数据
fun requestTaskDetail(taskDetailToBean: TaskDetailToBean){
LogUit.printI(TAG,"获取详情:json="+ Gson().toJson(taskDetailToBean))
HTTPProxy.instance!!.execute( this,taskDetailToBean, Constant.REQUEST_TASK_DETAIL);
}
如注释所言,只要在订阅时使用
`as`(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner)))
就可以绑定lifecycleOwner,从而跟随生命周期自动取消订阅
这样,只要在网略请求回调时(这里给出栗子):
//网略请求回调
override fun <T> onResponse(observable: Observable<T>, typeLogin: Int) {
try {
//业务请求类型
when (typeLogin) {
//获取任务请求
Constant.REQUEST_TASK -> taskLiveData.postValue(observable as (Observable<TaskBean>))
//获取任务详情请求
Constant.REQUEST_TASK_DETAIL ->taskDetailLiveData.postValue(observable as (Observable<TaskDetailBean>))
}
} catch (e :Exception){
e.printStackTrace();
}
}
调用taskLiveData.postValue(observable as (Observable<TaskBean>))
更新数据即可,taskLiveData只会在Activity处于活动状态下处理(常见网略请求回调后更新UI,此时如果UI所在的Activity已消亡就会引发错误),在liveData里面处理网略请求回调的数据就不会造成资源浪费,然后又在Activity消亡时自动取消订阅,就不会引发内存泄漏
- View中使用
val testModel by lazy { ViewModelProviders.of(this).get(TestNodel::class.java) }//绑定lifeCycleOwner,获取ViewModel
...
testModel.initData(this)
testModel.requestTaskDetail(taskDetailToBean)
这里省略去部分代码,总之,在网略请求之后,会调用自定义的一个接口,回调上面给出的onResponse方法,然后更新liveData的数据。网略请求使用的是一个rxjava+retrofit+okhttp自己封装的工具,代码就不给出了。
- 测试
网上有段很内存泄漏的代码,很好测试内存泄漏,这里给出来以供测试时复制粘贴
Observable.interval(1, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : io.reactivex.Observer<Long>{
override fun onComplete() {
LogUit.printI(RegisterOrLoginModel.TAG,"onComplete")
}
override fun onSubscribe(d: Disposable) {
LogUit.printI(RegisterOrLoginModel.TAG,"onSubscribe:d=$d")
}
override fun onNext(t: Long) {
LogUit.printI(RegisterOrLoginModel.TAG,"onNext:t=$t,")
}
override fun onError(e: Throwable) {
LogUit.printI(RegisterOrLoginModel.TAG,"onError=${e.message}")
}
})
测试的方法是这样的:定义两个Activity:A和B,从A跳转到B,B持有栗子中的TestViewModel,然后在taskLiveData.observe(```)方法的处理中添加这段代码,每个一秒就会打印log一次,然后按返回键回到A,停止Log打印,如果不加上
`as`(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner)))
则会一直打印log,发生内存泄漏。
3.注意
AutoDispose的版本已经更新到1.3.0了,如果使用超过1.0.0的版本(目前只测试到这个版本),绑定lifecycleOwner时就会要求使用androidx里面的lifecycleOwner,这将与LiveData的1.1.0版本冲突(笔者只试了下这个版本),因为LiveData要求的lifecycleOwner是android.arch.lifecycle.LifecycleOwner的,笔者尚未找到可以同时满足这两个条件的Activity(其实是没去找哈哈)
另外,本文代码使用kotlin写,还在使用java的要去更新一下技能了,使用kotlin不用担心以前的java代码不能使用,因为从java转换成kotlin非常容易!!!
原创文章