LiveData+ViewModel+RxJava2+autoDisposable解決內(nèi)存泄漏

0.前言

使用Rxjava的人越來越多厘唾,rxjava現(xiàn)在已經(jīng)更新到rxjava3了巾钉,因其簡潔效率高的特點備受程序猿喜愛。然而由rxjava處理不但引起的內(nèi)存泄漏問題也不得不讓人頭疼,每次使用完都要手動取消掉訂閱也很麻煩而且不一定執(zhí)行滔驶。為了解決這個問題,由此誕生了rxlifecycle卿闹,使用rxlifecycle可以跟蹤lifeOwnner的生命周期從而自動取消訂閱揭糕,但是卻有許多限制和問題,詳情見 為什么不使用 RxLifecycle?,作者已經(jīng)在文章里面說了锻霎。文章最后還親自推薦使用AutoDisposable著角,連他本人都認為rxlifecycle不如AutoDisposable了。網(wǎng)上關于AutoDisposable和LiveData相關使用的文章有很多旋恼,但是卻找不到LiveData結合AutoDisposable一起使用的文章吏口,著實讓人費解。很明顯冰更,liveData使得代碼僅僅在Activity處于活動狀態(tài)下執(zhí)行产徊,如果代碼使用了Rxjava訂閱處理數(shù)據(jù)(在網(wǎng)略請求中很常見,網(wǎng)略請求經(jīng)常使用Retrofit+okhttp+Rxjava蜀细,詳情見筆者另一篇文章 使用Kotlin+Rretrofit+rxjava+設計模式+MVP封裝網(wǎng)絡請求),這個時候如果不及時取消訂閱囚痴,則會引起內(nèi)存泄漏

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,專門負責處理數(shù)據(jù)
class TestModel:ViewModel(){
    val taskLiveData= MutableLiveData<Observable<TaskBean>>()//ViewModel內(nèi)部持有LiveData
    fun initData( lifecycleOwner: LifecycleOwner){
        //此處選擇在TestModel內(nèi)部處理LiveData(網(wǎng)上教程很多是把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) {
                                //處理網(wǎng)略錯誤
                            }

                        })
            }

        })
    }
}

 //網(wǎng)略請求獲取數(shù)據(jù)
    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奕谭,從而跟隨生命周期自動取消訂閱
這樣,只要在網(wǎng)略請求回調(diào)時(這里給出栗子):

 //網(wǎng)略請求回調(diào)
    override fun <T> onResponse(observable: Observable<T>, typeLogin: Int) {
        try {
            //業(yè)務請求類型
            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();
        }
    }

調(diào)用taskLiveData.postValue(observable as (Observable<TaskBean>))更新數(shù)據(jù)即可痴荐,taskLiveData只會在Activity處于活動狀態(tài)下處理(常見網(wǎng)略請求回調(diào)后更新UI血柳,此時如果UI所在的Activity已消亡就會引發(fā)錯誤),在liveData里面處理網(wǎng)略請求回調(diào)的數(shù)據(jù)就不會造成資源浪費生兆,然后又在Activity消亡時自動取消訂閱难捌,就不會引發(fā)內(nèi)存泄漏

  • View中使用
val testModel by lazy { ViewModelProviders.of(this).get(TestNodel::class.java) }//綁定lifeCycleOwner,獲取ViewModel
...
testModel.initData(this)
testModel.requestTaskDetail(taskDetailToBean)

這里省略去部分代碼鸦难,總之根吁,在網(wǎng)略請求之后,會調(diào)用自定義的一個接口合蔽,回調(diào)上面給出的onResponse方法击敌,然后更新liveData的數(shù)據(jù)。網(wǎng)略請求使用的是一個rxjava+retrofit+okhttp自己封裝的工具拴事,代碼就不給出了沃斤。

  • 測試
    網(wǎng)上有段很內(nèi)存泄漏的代碼,很好測試內(nèi)存泄漏刃宵,這里給出來以供測試時復制粘貼
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跳轉(zhuǎn)到B,B持有栗子中的TestViewModel牲证,然后在taskLiveData.observe(```)方法的處理中添加這段代碼哮针,每個一秒就會打印log一次,然后按返回鍵回到A坦袍,停止Log打印诚撵,如果不加上

`as`(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner)))

則會一直打印log,發(fā)生內(nèi)存泄漏键闺。

3.注意

AutoDispose的版本已經(jīng)更新到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轉(zhuǎn)換成kotlin非常容易!D洹嘴高!
原創(chuàng)文章

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末竿音,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拴驮,更是在濱河造成了極大的恐慌春瞬,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件套啤,死亡現(xiàn)場離奇詭異宽气,居然都是意外死亡,警方通過查閱死者的電腦和手機潜沦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評論 3 395
  • 文/潘曉璐 我一進店門萄涯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人唆鸡,你說我怎么就攤上這事涝影。” “怎么了喇闸?”我有些...
    開封第一講書人閱讀 164,911評論 0 354
  • 文/不壞的土叔 我叫張陵袄琳,是天一觀的道長。 經(jīng)常有香客問我燃乍,道長唆樊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,737評論 1 294
  • 正文 為了忘掉前任刻蟹,我火速辦了婚禮逗旁,結果婚禮上,老公的妹妹穿的比我還像新娘舆瘪。我一直安慰自己片效,他們只是感情好,可當我...
    茶點故事閱讀 67,753評論 6 392
  • 文/花漫 我一把揭開白布英古。 她就那樣靜靜地躺著淀衣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪召调。 梳的紋絲不亂的頭發(fā)上膨桥,一...
    開封第一講書人閱讀 51,598評論 1 305
  • 那天,我揣著相機與錄音唠叛,去河邊找鬼只嚣。 笑死,一個胖子當著我的面吹牛艺沼,可吹牛的內(nèi)容都是我干的册舞。 我是一名探鬼主播,決...
    沈念sama閱讀 40,338評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼障般,長吁一口氣:“原來是場噩夢啊……” “哼调鲸!你這毒婦竟也來了盛杰?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,249評論 0 276
  • 序言:老撾萬榮一對情侶失蹤线得,失蹤者是張志新(化名)和其女友劉穎饶唤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體贯钩,經(jīng)...
    沈念sama閱讀 45,696評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡募狂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,888評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了角雷。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片祸穷。...
    茶點故事閱讀 40,013評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖勺三,靈堂內(nèi)的尸體忽然破棺而出雷滚,到底是詐尸還是另有隱情,我是刑警寧澤吗坚,帶...
    沈念sama閱讀 35,731評論 5 346
  • 正文 年R本政府宣布祈远,位于F島的核電站,受9級特大地震影響商源,放射性物質(zhì)發(fā)生泄漏车份。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,348評論 3 330
  • 文/蒙蒙 一牡彻、第九天 我趴在偏房一處隱蔽的房頂上張望扫沼。 院中可真熱鬧,春花似錦庄吼、人聲如沸缎除。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽磺浙。三九已至缩歪,卻和暖如春萨咕,著一層夾襖步出監(jiān)牢的瞬間化漆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評論 1 270
  • 我被黑心中介騙來泰國打工殊轴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人袒炉。 一個月前我還...
    沈念sama閱讀 48,203評論 3 370
  • 正文 我出身青樓旁理,卻偏偏與公主長得像,于是被迫代替她去往敵國和親我磁。 傳聞我的和親對象是個殘疾皇子孽文,可洞房花燭夜當晚...
    茶點故事閱讀 44,960評論 2 355