LiveData+ViewModel+RxJava2+autoD

作者: 雯艺雪 | 来源:发表于2019-08-14 15:26 被阅读7次

    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非常容易!!!
    原创文章

    相关文章

      网友评论

        本文标题:LiveData+ViewModel+RxJava2+autoD

        本文链接:https://www.haomeiwen.com/subject/jlddjctx.html