RxLifecycle
目的:解決RxJava
使用中的內存泄漏問題。android
例如,當使用RxJava
訂閱並執行耗時任務後,當Activity
被finish
時,若是耗時任務還未完成,沒有及時取消訂閱,就會致使Activity
沒法被回收,從而引起內存泄漏。git
爲了解決這個問題,就產生了RxLifecycle
,讓RxJava
變得有生命週期感知,使得其能及時取消訂閱,避免出現內存泄漏問題。github
首先來介紹下RxLifecycle
的使用。數組
implementation 'com.trello.rxlifecycle2:rxlifecycle:2.2.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle-android:2.2.1'
implementation 'com.trello.rxlifecycle2:rxlifecycle-components:2.2.1'
複製代碼
Activity/Fragment
須要繼承RxAppCompatActivity/RxFragment
,主要支持以下幾種容器類: bash
Rx
類便可,這一步主要是對生命週期的回調事件進行監聽。
以Activity
爲例,主要有以下兩種方法:app
bindUntilEvent(@NonNull ActivityEvent event)
複製代碼
bindToLifecycle()
複製代碼
針對Fragment
也有一樣的兩種方法,只是方法名會有所不一樣。ide
下面詳細介紹這兩種方法的區別:函數
bindUntilEvent
該方法指定在哪一個生命週期方法調用時取消訂閱。學習
其中ActivityEvent
是一個枚舉類,對應於Activity
的生命週期。ui
public enum ActivityEvent {
CREATE,
START,
RESUME,
PAUSE,
STOP,
DESTROY
}
複製代碼
具體使用示例:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Observable.interval(1, TimeUnit.SECONDS)
.doOnDispose {
Log.i(TAG, "Unsubscribing subscription from onDestory()")
}
.compose(bindUntilEvent(ActivityEvent.DESTROY))
.subscribe {
Log.i(TAG, "Started in onCreate(), running until in onDestroy(): $it")
}
}
複製代碼
指定在生命週期onDestory()
時,取消訂閱。
bindToLifecycle
在某個生命週期進行綁定,在對應的生命週期進行訂閱解除。
具體使用示例:
override fun onResume() {
super.onResume()
Observable.interval(1, TimeUnit.SECONDS)
.doOnDispose {
Log.i(TAG, "Unsubscribing subscription from onPause()")
}
.compose(bindToLifecycle())
.subscribe {
Log.i(TAG, "Started in onResume(), running until in onPause(): $it")
}
}
複製代碼
在onResume()
進行綁定訂閱,則在onPause()
進行解除訂閱,生命週期是兩兩對應的。
compose
首先來了解一下compose
操做符。
compose(bindToLifecycle())
compose(bindUntilEvent(ActivityEvent.DESTROY))
複製代碼
如上所示,兩種綁定生命週期的方式,都是經過compose
操做符進行實現的。
compose
通常狀況下能夠配合Transformer
使用,以實現將一種類型的Observable
轉換成另外一種類型的Observable
,保證調用的鏈式結構。
那麼接下來看該操做符在RxLifecycle
中的應用,從bindToLifecycle
和bindUntilEvent
入手。
BehaviorSubject
public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {
private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();
@Override
@NonNull
@CheckResult
public final Observable<ActivityEvent> lifecycle() {
return lifecycleSubject.hide();
}
@Override
@NonNull
@CheckResult
public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) {
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
}
@Override
@NonNull
@CheckResult
public final <T> LifecycleTransformer<T> bindToLifecycle() {
return RxLifecycleAndroid.bindActivity(lifecycleSubject);
}
@Override
@CallSuper
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lifecycleSubject.onNext(ActivityEvent.CREATE);
}
@Override
@CallSuper
protected void onStart() {
super.onStart();
lifecycleSubject.onNext(ActivityEvent.START);
}
@Override
@CallSuper
protected void onResume() {
super.onResume();
lifecycleSubject.onNext(ActivityEvent.RESUME);
}
@Override
@CallSuper
protected void onPause() {
lifecycleSubject.onNext(ActivityEvent.PAUSE);
super.onPause();
}
@Override
@CallSuper
protected void onStop() {
lifecycleSubject.onNext(ActivityEvent.STOP);
super.onStop();
}
@Override
@CallSuper
protected void onDestroy() {
lifecycleSubject.onNext(ActivityEvent.DESTROY);
super.onDestroy();
}
}
複製代碼
RxAppCompatActivity
中有一個關鍵對象BehaviorSubject
BehaviorSubject
會發送離訂閱最近的上一個值,沒有上一個值的時候會發送默認值。以下圖:
因此lifecycleSubject
會根據綁定訂閱的時期,不斷髮送接下來的生命週期事件ActivityEvent
。
LifecycleTransformer
接下來繼續看源碼,bindToLifecycle
和bindUntilEvent
都返回了一個LifecycleTransformer
對象,那麼LifecycleTransformer
到底有什麼用?
@ParametersAreNonnullByDefault
public final class LifecycleTransformer<T> implements ObservableTransformer<T, T>,
FlowableTransformer<T, T>,
SingleTransformer<T, T>,
MaybeTransformer<T, T>,
CompletableTransformer
{
final Observable<?> observable;
LifecycleTransformer(Observable<?> observable) {
checkNotNull(observable, "observable == null");
this.observable = observable;
}
@Override
public ObservableSource<T> apply(Observable<T> upstream) {
return upstream.takeUntil(observable);
}
@Override
public Publisher<T> apply(Flowable<T> upstream) {
return upstream.takeUntil(observable.toFlowable(BackpressureStrategy.LATEST));
}
@Override
public SingleSource<T> apply(Single<T> upstream) {
return upstream.takeUntil(observable.firstOrError());
}
@Override
public MaybeSource<T> apply(Maybe<T> upstream) {
return upstream.takeUntil(observable.firstElement());
}
@Override
public CompletableSource apply(Completable upstream) {
return Completable.ambArray(upstream, observable.flatMapCompletable(Functions.CANCEL_COMPLETABLE));
}
@Override
public boolean equals(Object o) {
if (this == o) { return true; }
if (o == null || getClass() != o.getClass()) { return false; }
LifecycleTransformer<?> that = (LifecycleTransformer<?>) o;
return observable.equals(that.observable);
}
@Override
public int hashCode() {
return observable.hashCode();
}
@Override
public String toString() {
return "LifecycleTransformer{" +
"observable=" + observable +
'}';
}
}
複製代碼
LifecycleTransformer
實現了各類Transformer
接口,可以將一個 Observable/Flowable/Single/Completable/Maybe
對象轉換成另外一個 Observable/Flowable/Single/Completable/Maybe
對象。正好配合上文的compose
操做符,使用在鏈式調用中。
takeUntil
接下來到了關鍵了,LifecycleTransformer
到底把原來的Observable
對象轉換成了什麼樣子?
這就須要瞭解takeUntil
操做符了!
Observable
發射了一項數據或者終止時,丟棄原
Observable
發射的任何數據。所謂的第二個
Observable
,即傳入
takeUntil
中的
Observable
對象。
理解了該操做符的做用,那麼你可能就明白了,RxLifecycle
就是經過監聽第二個Observable
發射的數據,來解除訂閱。
那麼這第二個Observable
是誰?
不就是在建立LifecycleTransformer
的時候傳入構造函數中的嘛,那就來尋找一下何時建立的該對象便可。
從頭開始捋一捋:
public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) {
return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
}
複製代碼
該方法返回了LifecycleTransformer
對象,繼續向下追溯。
public static <T, R> LifecycleTransformer<T> bindUntilEvent(@Nonnull final Observable<R> lifecycle,
@Nonnull final R event) {
checkNotNull(lifecycle, "lifecycle == null");
checkNotNull(event, "event == null");
return bind(takeUntilEvent(lifecycle, event));
}
private static <R> Observable<R> takeUntilEvent(final Observable<R> lifecycle, final R event) {
return lifecycle.filter(new Predicate<R>() {
@Override
public boolean test(R lifecycleEvent) throws Exception {
return lifecycleEvent.equals(event);
}
});
}
複製代碼
繼續追蹤,立刻接近真相。
public static <T, R> LifecycleTransformer<T> bind(@Nonnull final Observable<R> lifecycle) {
return new LifecycleTransformer<>(lifecycle);
}
複製代碼
在該方法中建立了該對象,並傳入了一個Observable
對象,經過上面方法便可知道該對象就是BehaviorSubject
對象。
那麼該對象在何時發送第一次數據呢?
這就要看上面的takeUntilEvent
方法了。
關鍵在這一句lifecycleEvent.equals(event)
,只有當BehaviorSubject
發送的ActivityEvent
的值等於解除綁定的生命週期時,纔會發送第一次數據。那麼當發送第一次數據時,根據上面的分析就會解除訂閱的綁定。
那麼針對bindToLifecycle
方法,是進行怎樣的操做,使得在對應的生命週期進行解除訂閱呢?
仍是繼續看源碼。
public final <T> LifecycleTransformer<T> bindToLifecycle() {
return RxLifecycleAndroid.bindActivity(lifecycleSubject);
}
複製代碼
public static <T> LifecycleTransformer<T> bindActivity(@NonNull final Observable<ActivityEvent> lifecycle) {
return bind(lifecycle, ACTIVITY_LIFECYCLE);
}
複製代碼
其中ACTIVITY_LIFECYCLE
爲:
private static final Function<ActivityEvent, ActivityEvent> ACTIVITY_LIFECYCLE =
new Function<ActivityEvent, ActivityEvent>() {
@Override
public ActivityEvent apply(ActivityEvent lastEvent) throws Exception {
switch (lastEvent) {
case CREATE:
return ActivityEvent.DESTROY;
case START:
return ActivityEvent.STOP;
case RESUME:
return ActivityEvent.PAUSE;
case PAUSE:
return ActivityEvent.STOP;
case STOP:
return ActivityEvent.DESTROY;
case DESTROY:
throw new OutsideLifecycleException("Cannot bind to Activity lifecycle when outside of it.");
default:
throw new UnsupportedOperationException("Binding to " + lastEvent + " not yet implemented");
}
}
};
複製代碼
該函數的功能是會根據傳入的生命週期事件,返回對應的生命週期,如CREATE
→DESTROY
。看來經過該函數就能夠實如今對應生命週期解綁了。
不過還須要一系列操做符的協助,繼續看源碼。
public static <T, R> LifecycleTransformer<T> bind(@Nonnull Observable<R> lifecycle,
@Nonnull final Function<R, R> correspondingEvents) {
checkNotNull(lifecycle, "lifecycle == null");
checkNotNull(correspondingEvents, "correspondingEvents == null");
return bind(takeUntilCorrespondingEvent(lifecycle.share(), correspondingEvents));
}
private static <R> Observable<Boolean> takeUntilCorrespondingEvent(final Observable<R> lifecycle,
final Function<R, R> correspondingEvents) {
return Observable.combineLatest(
lifecycle.take(1).map(correspondingEvents),
lifecycle.skip(1),
new BiFunction<R, R, Boolean>() {
@Override
public Boolean apply(R bindUntilEvent, R lifecycleEvent) throws Exception {
return lifecycleEvent.equals(bindUntilEvent);
}
})
.onErrorReturn(Functions.RESUME_FUNCTION)
.filter(Functions.SHOULD_COMPLETE);
}
複製代碼
詳細看一下takeUntilCorrespondingEvent
方法。
take
首先看一下take
操做符,很簡單。
take(int)
用一個整數n做爲一個參數,只發射前面的n項,以下圖:
那麼對應lifecycle.take(1).map(correspondingEvents)
,即獲取發送的第一個生命週期事件,再經過上面對應的函數,轉換爲響應的生命週期。若是在onCreate
中進行綁定,那麼第一個發送的就是CREATE
,返回的就是對應的DESTORY
。
skip
skip(int)
忽略Observable
發射的前n項數據
lifecycle.skip(1)
,若是在onCreate
中進行綁定,那麼剩餘的就是START
,RESUME
,PAUSE
,STOP
,DESTROY
combineLatest
最後還須要一個關鍵的操做符combineLatest
,來完成對應生命週期的解除訂閱。
combineLatest
操做符能夠將2~9個Observable
發射的數據組裝起來而後再發射出來。不過還有兩個前提:
Observable
發射一個數據,就將全部Observable
最新發射的數據按照提供的函數組裝起來發射出去。具體示例,以下圖所示:
按照第三個參數的函數,將lifecycle.take(1).map(correspondingEvents)
和lifecycle.skip(1)
,進行combine
new BiFunction<R, R, Boolean>() {
@Override
public Boolean apply(R bindUntilEvent, R lifecycleEvent) throws Exception {
return lifecycleEvent.equals(bindUntilEvent);
}
}
複製代碼
那麼結果是
false,false,false,false,true
複製代碼
以後的onErrorReturn
和filter
是對異常的處理和判斷是否應該結束訂閱:
//異常處理
static final Function<Throwable, Boolean> RESUME_FUNCTION = new Function<Throwable, Boolean>() {
@Override
public Boolean apply(Throwable throwable) throws Exception {
if (throwable instanceof OutsideLifecycleException) {
return true;
}
//noinspection ThrowableResultOfMethodCallIgnored
Exceptions.propagate(throwable);
return false;
}
};
//是否應該取消訂閱,依賴於上游的boolean
static final Predicate<Boolean> SHOULD_COMPLETE = new Predicate<Boolean>() {
@Override
public boolean test(Boolean shouldComplete) throws Exception {
return shouldComplete;
}
};
複製代碼
因此,按照上面的例子,若是在onCreate()
方法中進行綁定,那麼在onDestory()
方法中就會對應的解除訂閱。
經過上面的分析,能夠了解RxLifecycle
的使用以及原理。
學習RxLifecycle
的過程當中,更加體會到了對於觀察者模式的使用,以及RxJava
操做符的強大,各類操做符幫咱們實現一些列的轉換。