RxLifecycle源码学习

使用RxJava引起的内存泄漏

RxJava很好用,但是随着订阅的增多内存开销也会随之增大,尤其是在配合使用网络请求的时候,当页面被finish,此时订阅逻辑还未完成,如果没有及时取消订阅,就会导致Activity/Fragment无法被回收,从而引发内存泄漏。

当我们不需要的时候,主动取消订阅。比如在下面的代码中,我们开启一个周期任务用来不断的输出信息,那么我们需要在该Activity被销毁的时候调用mSubscription.unsubscribe()来主动的解除订阅关系防止内存泄漏。

 @Override
 protected void onDestroy() {
     super.onDestroy();
     //主动解除订阅关系
     if (mSubscription != null && !mSubscription.isUnsubscribed()) {
         mSubscription.unsubscribe();
     }
 }

看完上面简单的示例,想必你也明白rxjava所造成的内存泄漏往往和组件的生命周期相关。也就是我们要重点关注那些在在组件销毁之后,订阅关系却仍然存在的情况。大部分情况下,当我们的视图销毁之后,订阅关系就没有必要存在了,所以需要我们主动取消订阅即可。

在我们的工程中,往往存在很多个视图(Activity,Fragment等),如果在每个视图当中都要手动的解除订阅关系是件很繁琐的事情。这里有两种方式:一是在基类当中,比如BaseActivity,BaseFragment中统一取消订阅,另外一种方式就是使用RxLifeCycle这个库。

RxLifecycle

RxLifeCycle主要提供了两个方法bindToLifecycle()和bindUntilEvent(),分别用来绑定生命周期和事件。

bindToLifecycle( )

绑定生命周期的做法本质上是通过监听组件(Activity,Fragment)生命周期的变化来自动解除订阅关系。用法如下:

 // Using automatic unsubscription, this should determine that the correct time to
 // unsubscribe is onStop (the opposite of onStart).
  Observable.interval(1, TimeUnit.SECONDS)
      .doOnDispose(new Action() {
          @Override
          public void run() throws Exception {
              Log.i(TAG, "Unsubscribing subscription from onStart()");
          }
      })
      .compose(this.<Long>bindToLifecycle())
      .subscribe(new Consumer<Long>() {
          @Override
          public void accept(Long num) throws Exception {
              Log.i(TAG, "Started in onStart(), running until in onStop(): " + num);
          }
      });
  • 在onResume中绑定,将在对应的onPause()方法中解除订阅关系
  • 在onStart()中绑定,将在对应的onStop()中解除订阅关系
  • 在onCreate()中绑定,将在对应的onDestory()中解除订阅关系

bindUntilEvent()

和使用bindToLifecycle()不一样的是,绑定事件的方式只关心何时解除订阅关系。因为在很多情况下,我们所做的操作并不一定是在onResume()开始,在onPause()结束,此时显然不能用绑定生命周期的方法。来看看绑定事件如何使用:

// `this.<Long>` is necessary if you're compiling on JDK7 or below.
// If you're using JDK8+, then you can safely remove it.
Observable.interval(1, TimeUnit.SECONDS)
    .doOnDispose(new Action() {
        @Override
        public void run() throws Exception {
            Log.i(TAG, "Unsubscribing subscription from onResume()");
        }
    })
    .compose(this.<Long>bindUntilEvent(ActivityEvent.DESTROY))
    .subscribe(new Consumer<Long>() {
        @Override
        public void accept(Long num) throws Exception {
            Log.i(TAG, "Started in onResume(), running until in onDestroy(): " + num);
        }
    });

注:如果你使用的是JDK7或更低版本,要在bindUntilEvent()方法前加this.。

从bindUntilEvent(ActivityEvent.DESTROY);开始

public abstract class RxAppCompatActivity extends AppCompatActivity implements LifecycleProvider<ActivityEvent> {

    private final BehaviorSubject<ActivityEvent> lifecycleSubject = BehaviorSubject.create();

    @Override
    @NonNull
    @CheckResult
    public final <T> LifecycleTransformer<T> bindUntilEvent(@NonNull ActivityEvent event) {
        return RxLifecycle.bindUntilEvent(lifecycleSubject, event);
    }

    //省略其他代码
}

一、BehaviorSubject是什么?

点开 RxJava2文档 ,找到关于Subject的描述:

public abstract class Subject<T>
extends Observable<T>
implements Observer<T>

这里写图片描述

对于Observable,Observer,Subscriber我们比较熟悉,故不做说明,重点来看Subject。

通过上面的图我们可以看出Subject继承自Observable,也就意味着Subject可以作为被观察者,另外,它又实现了Observer接口,这意味着它也可以作为观察者。不难看出,Subject既能作为Observer订阅Observable,又能作为Observable被其他Observer订阅。总之,Subject承担了这么一种角色:对上作为观察者,对下作为被观察者。

二、常见的Subject

从上面的uml中我们看出,RxJava为我们提供了四种常用的Subject,即
AsyncSubject,BehabviorSubject,PublishSubject,ReplaySubject,下面我们对这四者进行说明。

1.AsyncSubject

An Subject that emits the very last value followed by a completion event or the received error to Observers.

AsyncSubject会缓存最后一个数据并在调用onCompleted()时将该数据发送给订阅者,在该过程中,一旦发生任何异常都不会发送数据到订阅者,而是发送给订阅者一个异常通知,即订阅者只能接受到一个异常的通知。

举例来说明AsyncSubject的用法:

asyncSubject.onNext("1");
asyncSubject.onNext("2");
asyncSubject.onCompleted();//必须调用才会开始发送数据

以上代码执行后,订阅者接受到的数据是2.

2.BehabviorSubject

Subject that emits the most recent item it has observed and all subsequent observed items to each subscribed Observer.

当BehaviorSubject被订阅后,它首先会发送原始Observable最近发射的数据,如果最近没有,会发射一个默认值,接下继续发射原始Observable的数据。

这里写图片描述

例子如下:

 // observer will receive all 4 events (including "default").
  BehaviorSubject<Object> subject = BehaviorSubject.createDefault("default");
  subject.subscribe(observer);
  subject.onNext("one");
  subject.onNext("two");
  subject.onNext("three");

  // observer will receive the "one", "two" and "three" events, but not "zero"
  BehaviorSubject<Object> subject = BehaviorSubject.create();
  subject.onNext("zero");
  subject.onNext("one");
  subject.subscribe(observer);
  subject.onNext("two");
  subject.onNext("three");

  // observer will receive only onComplete
  BehaviorSubject<Object> subject = BehaviorSubject.create();
  subject.onNext("zero");
  subject.onNext("one");
  subject.onComplete();
  subject.subscribe(observer);

  // observer will receive only onError
  BehaviorSubject<Object> subject = BehaviorSubject.create();
  subject.onNext("zero");
  subject.onNext("one");
  subject.onError(new RuntimeException("error"));
  subject.subscribe(observer);

3.PublishSubject

Subject that, once an Observer has subscribed, emits all subsequently observed items to the subscriber.

Observable一旦被订阅就开始发送事件,如下图所示:

这里写图片描述

例子:

 PublishSubject<Object> subject = PublishSubject.create();
 // observer1 will receive all onNext and onComplete events
 subject.subscribe(observer1);
 subject.onNext("one");
 subject.onNext("two");
 // observer2 will only receive "three" and onComplete
 subject.subscribe(observer2);
 subject.onNext("three");
 subject.onComplete();

4.ReplaySubject

Replays events to Observers.

ReplaySubject会缓存所有已经发射的数据,当一个新的订阅关系产生时,ReplaySuject会将所有数据都发送给他。如下图:

这里写图片描述

 ReplaySubject<Object> subject = new ReplaySubject<>();
 subject.onNext("one");
 subject.onNext("two");
 subject.onNext("three");
 subject.onComplete();

 // both of the following will get the onNext/onComplete calls from above
 subject.subscribe(observer1);
 subject.subscribe(observer2);
Subject
AsyncSubject不论订阅发生在什么时候,只会发射最后一个数据
BehaviorSubject发送订阅之前一个数据和订阅之后的全部数据
ReplaySubject不论订阅发生在什么时候,都发射全部数据
PublishSubject发送订阅之后全部数据

三、RxLifecycle.bindUntilEvent()

我们回过头来重新看之前的完整的源码:

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();
   }
}

可以看到RxLifecycle.bindUntilEvent()这个函数的返回值类型是LifecycleTransformer,这个类实现了ObservableTransformer接口,主要功能如下:

 @Override
 public ObservableSource<T> apply(Observable<T> upstream) {
     return upstream.takeUntil(observable);
 }

TakeUtil操作符

takeUntil订阅原始的Observable并发射数据,此外它还监视你提供的第二个Observable。当第二个Observable发射了一项数据或者发射一项终止的通知时(onError通知或者onCompleted通知),TakeUntil返回的Observable会停止发射原始的Observable,如下图所示:

这里写图片描述

到现在为止,我们已经知道了RxLifeCycle利用BehaviorSubject来监视生命周期的变化,用takeUtil操作符让原有的Observable(比如网络请求的Observable)来监视Subject发射的数据呢,并根据Subject的状态自动停止原始数据的发射。

跟进bindUntilEvent()方法:

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);
          }
      });
  }

通过filter操作符进行过滤,只有绑定的事件与BehaviorSubject在AppCompatActivity各个生命周期发射的事件相同的时候,才提交给订阅者,让他自动停止原始数据的发射。

至此,这个开源生命周期管理框架分析结束。

谢谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值