RxLifecycle詳細解析

1、介紹

RxLifecycle目的:解決RxJava使用中的內存泄漏問題。android

例如,當使用RxJava訂閱並執行耗時任務後,當Activityfinish時,若是耗時任務還未完成,沒有及時取消訂閱,就會致使Activity沒法被回收,從而引起內存泄漏。git

爲了解決這個問題,就產生了RxLifecycle,讓RxJava變得有生命週期感知,使得其能及時取消訂閱,避免出現內存泄漏問題。github

2、使用

首先來介紹下RxLifecycle的使用。數組

1.添加依賴

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'
複製代碼

2.繼承容器類

Activity/Fragment須要繼承RxAppCompatActivity/RxFragment,主要支持以下幾種容器類: bash

只須要在項目中針對base類的容器中繼承實現對應的 Rx類便可,這一步主要是對生命週期的回調事件進行監聽。

3.綁定容器生命週期

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()進行解除訂閱,生命週期是兩兩對應的。

3、原理解析

1.compose

首先來了解一下compose操做符。

compose(bindToLifecycle())
compose(bindUntilEvent(ActivityEvent.DESTROY))
複製代碼

如上所示,兩種綁定生命週期的方式,都是經過compose操做符進行實現的。

compose通常狀況下能夠配合Transformer使用,以實現將一種類型的Observable轉換成另外一種類型的Observable,保證調用的鏈式結構。

那麼接下來看該操做符在RxLifecycle中的應用,從bindToLifecyclebindUntilEvent入手。

2.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

3.LifecycleTransformer

接下來繼續看源碼,bindToLifecyclebindUntilEvent都返回了一個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操做符,使用在鏈式調用中。

4.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");
            }
        }
    };
複製代碼

該函數的功能是會根據傳入的生命週期事件,返回對應的生命週期,如CREATEDESTROY。看來經過該函數就能夠實如今對應生命週期解綁了。

不過還須要一系列操做符的協助,繼續看源碼。

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方法。

5.take

首先看一下take操做符,很簡單。

take(int)用一個整數n做爲一個參數,只發射前面的n項,以下圖:

那麼對應lifecycle.take(1).map(correspondingEvents),即獲取發送的第一個生命週期事件,再經過上面對應的函數,轉換爲響應的生命週期。若是在onCreate中進行綁定,那麼第一個發送的就是CREATE,返回的就是對應的DESTORY

6.skip

skip(int)忽略Observable發射的前n項數據

lifecycle.skip(1),若是在onCreate中進行綁定,那麼剩餘的就是STARTRESUMEPAUSESTOPDESTROY

7. combineLatest

最後還須要一個關鍵的操做符combineLatest,來完成對應生命週期的解除訂閱。

combineLatest操做符能夠將2~9個Observable發射的數據組裝起來而後再發射出來。不過還有兩個前提:

  • 全部的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
複製代碼

以後的onErrorReturnfilter是對異常的處理和判斷是否應該結束訂閱:

//異常處理
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()方法中就會對應的解除訂閱。

4、總結

經過上面的分析,能夠了解RxLifecycle的使用以及原理。

學習RxLifecycle的過程當中,更加體會到了對於觀察者模式的使用,以及RxJava操做符的強大,各類操做符幫咱們實現一些列的轉換。

相關文章
相關標籤/搜索