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
爲例,主要有以下兩種方法:markdown
bindUntilEvent(@NonNull ActivityEvent event) 複製代碼
bindToLifecycle() 複製代碼
針對Fragment
也有一樣的兩種方法,只是方法名會有所不一樣。app
下面詳細介紹這兩種方法的區別:ide
bindUntilEvent
該方法指定在哪一個生命週期方法調用時取消訂閱。函數
其中ActivityEvent
是一個枚舉類,對應於Activity
的生命週期。oop
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
操做符的強大,各類操做符幫咱們實現一些列的轉換。