配色: 字号:
RxAndroid之Rxlifecycle使用
2016-12-20 | 阅:  转:  |  分享 
  
RxAndroid之Rxlifecycle使用



随着Android第三库的普及,RxJava和RxAndroid(https://github.com/ReactiveX/RxAndroid)越来越被人熟知,简洁的语法,配合Java8Lambda表达式,使代码的结构更加清晰,通过线程调度器更容易控制和切换线程,种种优点,使用它的人也越来越多。但是使用不好,很容易导致内存泄露。Rxlifecycle(https://github.com/trello/RxLifecycle)就使被用来严格控制由于发布了一个订阅后,由于没有及时取消,导致Activity/Fragment无法销毁导致的内存泄露。



开源项目



RxLifecycle地址:https://github.com/trello/RxLifecycle。



该项目是为了防止RxJava中subscription导致内存泄漏而诞生的,核心思想是通过监听Activity、Fragment的生命周期,来自动断开subscription以防止内存泄漏。



Rxlifecycle使用非常方便简单,如下:



1.集成

build.gradle添加



//Rxlifecycle

compile''com.trello:rxlifecycle:0.3.1''

compile''com.trello:rxlifecycle-components:0.3.1''



//Rxjava

compile''io.reactivex:rxjava:1.0.16''



Components包中包含RxActivity、RxFragment等等,可以用Rxlifecycle提供的,也可以自定义。



2.Sample解析

官方sample源码:两种使用方法:



1.手动设置取消订阅的时机,例子1、例子3



2.绑定生命周期,自动取消订阅,例子2



publicclassMainActivityextendsRxAppCompatActivity{



//Note:Activity需要继承RxAppCompatActivity,fragment需要继承RxFragment,等等

//可以使用的组件在components包下面



privatestaticfinalStringTAG="RxLifecycle";



@Override

protectedvoidonCreate(BundlesavedInstanceState){

super.onCreate(savedInstanceState);

Log.d(TAG,"onCreate()");

setContentView(R.layout.activity_main);



//SpecificallybindthisuntilonPause()



//Note:例子1:

Observable.interval(1,TimeUnit.SECONDS)

.doOnUnsubscribe(newAction0(){

@Override

publicvoidcall(){

Log.i(TAG,"UnsubscribingsubscriptionfromonCreate()");

}

})

//Note:手动设置在activityonPause的时候取消订阅

.compose(this.bindUntilEvent(ActivityEvent.PAUSE))

.subscribe(newAction1(){

@Override

publicvoidcall(Longnum){

Log.i(TAG,"StartedinonCreate(),runninguntilonPause():"+num);

}

});

}



@Override

protectedvoidonStart(){

super.onStart();

Log.d(TAG,"onStart()");



//Note:例子2:

//Usingautomaticunsubscription,thisshoulddeterminethatthecorrecttimeto

//unsubscribeisonStop(theoppositeofonStart).

Observable.interval(1,TimeUnit.SECONDS)

.doOnUnsubscribe(newAction0(){

@Override

publicvoidcall(){

Log.i(TAG,"UnsubscribingsubscriptionfromonStart()");

}

})

//Note:bindToLifecycle的自动取消订阅示例,因为是在onStart的时候调用,所以在onStop的时候自动取消订阅

.compose(this.bindToLifecycle())

.subscribe(newAction1(){

@Override

publicvoidcall(Longnum){

Log.i(TAG,"StartedinonStart(),runninguntilinonStop():"+num);

}

});

}



@Override

protectedvoidonResume(){

super.onResume();

Log.d(TAG,"onResume()");



//Note:例子3:

//`this.`isnecessaryifyou''recompilingonJDK7orbelow.

//Ifyou''reusingJDK8+,thenyoucansafelyremoveit.

Observable.interval(1,TimeUnit.SECONDS)

.doOnUnsuwww.baiyuewang.netbscribe(newAction0(){

@Override

publicvoidcall(){

Log.i(TAG,"UnsubscribingsubscriptionfromonResume()");

}

})

//Note:手动设置在activityonDestroy的时候取消订阅

.compose(this.bindUntilEvent(ActivityEvent.DESTROY))

.subscribe(newAction1(){

@Override

publicvoidcall(Longnum){

Log.i(TAG,"StartedinonResume(),runninguntilinonDestroy():"+num);

}

});

}

...



如下代码:



Observable.just("helloworld!")

.compose(this.bindUntilEvent(ActivityEvent.PAUSE))

.flatMap(newFunc1>(){

@Override

publicObservablecall(Strings){

returnObservable.interval(1,TimeUnit.SECONDS);

}

})



.subscribe(newAction1(){

@Override

publicvoidcall(LongaLong){

Log.i(TAG,"....oh,oh,no!!..........."+aLong);

}

});



activity生命周期paused的时候



Log.i(TAG,"....oh,oh,no!!..........."+aLong);



还会执行么??会会…



如果你想全部都不执行:



Observable.just("helloworld!")

.flatMap(newFunc1>(){

@Override

publicObservablecall(Strings){

returnObservable.interval(1,TimeUnit.SECONDS);

}

})

//fuck....here

.compose(this.bindUntilEvent(ActivityEvent.PAUSE))

.subscribe(newAction1(){

@Override

publicvoidcall(LongaLong){

Log.i(TAG,"....oh,oh,no!!..........."+aLong);

}

});



tip-2



Observable.interval(1,TimeUnit.SECONDS)

.doOnUnsubscribe(newAction0(){

@Override

publicvoidcall(){

Log.i(TAG,"Unsubscribingsubscription......");

}

})

.doOnNext(newAction1(){

@Override

publicvoidcall(LongaLong){

Log.i(TAG,"........fuck..........."+aLong);

}

})

.flatMap(newFunc1>(){

@Override

publicObservablecall(LongaLong){

returnObservable.just(aLong+"");

}

})

.compose(this.bindUntilEvent(ActivityEvent.PAUSE))

.subscribe(newAction1(){

@Override

publicvoidcall(Stringnum){

Log.i(TAG,"..........shit..........."+num);

}

});



activity在paused的时候,



Log.i(TAG,"........fuck..........."+aLong);

Log.i(TAG,"..........shit..........."+num);



都不会执行…而且会unsubscribe



延伸:

RxLifecycle-当Activity被destory时自动暂停网络请求



问题



Android开发中常会有这样一个场景:



发送网络请求->2.服务器处理请求并返回数据->3.client端接收数据,绘制UI。

在前两步一般都是不会出现问题的,但是在第三步,当数据返回给client端时,如果页面已经不在了,那么就无法去绘制UI,很有可能会导致意向不到的问题。因此,为了解决这个问题,一个好的思路就是当页面离开时,自动断开网络请求数据的处理过程,即数据返回后不再进行任何处理。



思考



要达到上面这样一个功能,我们可以思考,至少需要两部分:



随时监听Activity(Fragment)的生命周期并对外发射出去;

在我们的网络请求中,接收生命周期并进行判断,如果该生命周期是自己绑定的,如Destory,那么就断开数据向下传递的过程。



分析



可以看到,首先有一个核心功能要实现:就是既能够监听Activity生命周期事件并对外发射,又能够接收每一个生命周期事件并作出判断。为了实现这个功能,可以联想到RxJava中的Subject,既能够发射数据,又能够接收数据。



Subject介绍



了解Subject的读者可以跳过这部分。



如何理解Subject呢?



很容易,在RxJava里面,Observable是数据的发射者,它会对外发射数据,然后经过map、flatmap等等数据处理后,最终传递给Observer,这个数据接收者。因此,抛开中间数据处理不管,可以看出,Observable对外发射数据,是数据流的开端;Observer接收数据,是数据流的末端。



那么Subject呢?看一眼源码:



/

RepresentsanobjectthatisbothanObservableandanObserver.

/

publicabstractclassSubjectextendsObservableimplementsObserver{}



首先,它extendsObservable,说明Subject具备了对外发射数据的能力,即拥有了from()、just()等等;另外,它又implementsObserver,说明又能够处理数据,具备onNext()、onCompleted等等。



然后,Subject毕竟只是一个抽象类,那么我们要如何使用它呢?



这里介绍一种最简单的:PublishSubject:



PublishSubjectsubject=PublishSubject.create();

//myObserverwillreceive"one"&"two"andonCompletedevents

subject.subscribe(myObserver);

subject.onNext("one");

subject.onNext("two");

subject.onCompleted();



这里做的事情很简单,先创建一个PublishSubject->绑定一个myObserver,此时subject扮演了Observable的角色,把数据发射给myObserver->然后subject处理接收了两个数据one、two->最终这些数据都传递给了myObserver。所以,subject扮演的角色是:



数据one、two=>(Observer)subject(Observable)=>myObserver



简单来说,我们把数据one、two塞给subject,然后subject又发射给了myObserver。



BaseActivity监听生命周期



那么我们先来实现生命周期监听功能,基本思路是:在BaseActivity里创建一



个PublishSubject对象,在每个生命周期发生时,把该生命周期事件传递给PublishSubject。具体实现如下(只写部分生命周期,其他类似):



classBaseActivity{



protectedfinalPublishSubjectlifecycleSubject=PublishSubject.create();



@Override

protectedvoidonCreate(BundlesavedInstanceState){

lifecycleSubject.onNext(ActivityLifeCycleEvent.CREATE);

...

}



@Override

protectedvoidonPause(){

lifecycleSubject.onNext(ActivityLifeCycleEvent.PAUSE);

...

}



@Override

protectedvoidonStop(){

lifecycleSubject.onNext(ActivityLifeCycleEvent.STOP);

...

}

...



这样的话,我们把所有生命周期事件都传给了lifecycleSubject了,或者说,lifecycleSubject已经接收到了并能够对外发射各种生命周期事件的能力了。



改良每一个Observable,接收生命周期并自动断开自身



通常我们的一次网络请求长这样:



networkObservable

.subscribe(newObserver(handleUI()));



其中,networkObservable表示一个通用的网络请求,会接收网络数据并传递给Observer去绘制UI。



现在,我们希望这个networkObservable监听Activity的DESTORY事件,一旦发生了DESTORY就自动断开Observer,即使网络数据回来了也不再传递给Observer去绘制UI。即:



networkObservable

.compose(bindUntilEvent(ActivityLifeCycleEvent.DESTORY))

.subscribe(newObserver(handleUI()));



因此,我们需要实现



bindUntilEvent(ActivityLifeCycleEvent.DESTORY)



这个方法,那如何实现呢?



我们知道lifecycleSubject能够发射生命周期事件了,那么我们可以让networkObservable去检查lifecycleSubject发出的生命周期,如果和自己绑定的生命周期事件一样,那就自动停掉即可。



改装networkObservable



对于networkObservable自动停掉,我们可以利用操作符



networkObservable.takeUntil(otherObservable)



它的作用是监听otherObservable,一旦otherObservable对外发射了数据,就自动把networkObservable停掉;



那otherObservable何时对外发射数据呢?当然是lifecycleSubject发射出的生命周期事件等于绑定的生命周期事件时,开始发射。



otherObservable=lifecycleSubject.takeFirst(newFunc1(){

@Override

publicBooleancall(ActivityLifeCycleEventactivityLifeCycleEvent){

returnactivityLifeCycleEvent.equals(bindEvent);

}



其中的关键是判断activityLifeCycleEvent.equals(bindEvent);,一旦条件满足,otherObservable就对外发射数据,然后networkObservable就立即自动停掉。



合并生命周期监听与networkObservable改良



在BaseActivity里添加lifecycleSubject,并把每一个生命周期事件按时传递给lifecycleSubject

在BaseActivity里添加一个bindUntilEvent方法:

@NonNull

@Override

publicObservable.TransformerbindUntilEvent(@NonNullfinalActivityLifeCycleEventevent){

returnnewObservable.Transformer(){

@Override

publicObservablecall(ObservablesourceObservable){

ObservablecompareLifecycleObservable=

lifecycleSubject.takeFirst(newFunc1(){

@Override

publicBooleancall(ActivityLifeCycleEventactivityLifeCycleEvent){

returnactivityLifeCycleEvent.equals(event);

}

});

returnsourceObservable.takeUntil(compareLifecycleObservable);

}

};



在任意一个网络请求networkObservable处改良

networkObservable

.compose(bindUntilEvent(ActivityLifeCycleEvent.DESTORY))

.subscribe(newObserver(handleUI()));



注意:



文中提到的networkObservable是网络请求,但实际上这不限于网络请求,任何耗时操作如文件io操作等都可以利用这个方法,来监听生命周期并自动暂停。



对于Fragment中的处理方法也是类似。

献花(0)
+1
(本文系thedust79首藏)