RxLifecycle防内存泄漏分析

调用链的生成

以fragment为例,fragment继承RxLifecycle的RxFragment,然后在fragment中发起网络请求

// Retrofit生成的observable
Retrofit.create(xxx).subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .compose(fragment.bindUntilEvent(FragmentEvent.DETACH))
                .subscribe(new Observer<Response<T>>() {
                    @Override
                    public void onError(Throwable e) {
                        onResponseError(e);
                    }

                    @Override
                    public void onComplete() {
                        // do something
                    }

                    @Override
                    public void onSubscribe(Disposable d) {
                    }

                    @Override
                    public void onNext(Response<T> t) {
                        onResponse(t);
                    }
                });

生成的调用链如下

this = {ObservableTakeUntil@14202} 
 other = {ObservableFilter@14199} 
  predicate = {RxLifecycle$1@14208} 
   event = {FragmentEvent@14227} "DETACH"
  source = {BehaviorSubject@14209} 
 source = {ObservableObserveOn@14193} 
  scheduler = {HandlerScheduler@14188} 
  source = {ObservableUnsubscribeOn@14187} 
   scheduler = {IoScheduler@14181} 
   source = {ObservableSubscribeOn@14180} 
    scheduler = {IoScheduler@14181} 
    source = {CallExecuteObservable@14166} 

关键方法的调用

根据生成的调用链,最后调用的subscribe就是ObservableTakeUntil.subscribe()方法,它的subscribeActual()方法如下

@Override
public void subscribeActual(Observer<? super T> child) {
    final SerializedObserver<T> serial = new SerializedObserver<T>(child);

    final ArrayCompositeDisposable frc = new ArrayCompositeDisposable(2);

    final TakeUntilObserver<T> tus = new TakeUntilObserver<T>(serial, frc);

    child.onSubscribe(frc);

    other.subscribe(new TakeUntil(frc, serial));

    source.subscribe(tus);
}

这里的other是ObservableFilter,source是ObservableObserveOn,在other/source.subscribe()的调用中,通过调用链,会分别在BehaviorSubject/ObservableSubscribeOn.subscribeActual()中调用onSubscribe(),最终会调用到TakeUntil/TakeUntilObserver.onSubscribe(),在这里,会对frc赋值,赋值后,frc如下

this = {ArrayCompositeDisposable@6850}
 array = {Object[2]@6871} 
  0 = {ObservableObserveOn$ObserveOnObserver@6862} "0"
  1 = {ObservableFilter$FilterObserver@6852} 

dispose的调用

有两条路径会调用到dispose

ObservableTakeUntil.subscribeActual
 ObservableFilter.subscribeActual
  BehaviorSubject.subscribeActual
   BehaviorSubject$BehaviorDisposable.emitFirst
    // 这以后是真正的dispose流程
    BehaviorSubject$BehaviorDisposable.test
     NotificationLite.accept
      ObservableFilter$FilterObserver.onNext
       ObservableTakeUntil$TakeUntil.onNext // 这里在调用dipose的同时还调用了onCompete,通知到observer
        ArrayCompositeDisposable.dispose
         // 这里遍历frc并进行dispose
         ObservableObserveOn$ObserveOnObserver.dispose
          ObservableUnsubscribeOn$UnsubscribeObserver.dispose // 设置AtomicBoolean标识为true,表示已经dispose
           ObservableSubscribeOn$SubscribeOnObserver.dispose
            DisposableHelper.dispose
             CallExecuteObservable.dispose // 调用okHttpCall.cancel
            DisposableHelper.dispose
             scheduler.dispose
         ObservableFilter$FilterObserver
          BasicFuseableObserver.dispose
           BehaviorSubject$BehaviorDisposable.dispose // cancel设置为true

Fragment.onDetach
 BehaviorSubject.onNext(FragmentEvent.DETACH)
  BehaviorSubject$BehaviorDisposable.emitNext
   // 这以后是真正的dispose流程,同上
   BehaviorSubject$BehaviorDisposable.test

上面不同的observer都进行了dispose,具体的dispose不一样,比如终止okHttpCall,终止scheduler,设置标识位等。

如果:
1. 在发起请求之前就dispose,会走第一个分支,因为okHttpCall已经cancel,所以不会再发起请求
2. 在发起请求之后dispose,会走第二个分支,因为ObservableUnsubscribeOn$UnsubscribeObserver已经dispose,get() == true, 所以这里的onNext不会再进行任何操作,如下

@Override
public void onNext(T t) {
    if (!get()) {
        actual.onNext(t);
    }
}

由于在dispose中终止调用并进行了清理,同时还调用了onComplete,所以不会造成内存泄漏,也不会再回调到Activity/Fragment,造成可能的空指针等异常

总结

关键在两点:
1. 生成了ObservableTakeUntil,里面除了source之外,还生成了other,other根据predicate(条件)来定义behavior(行为),即当predicate.test为true时执行通过behavior调用ObserverFilterFilterObserver2.ObserverFilterFilterObserver实际上会再调用ObservableTakeUntil$TakeUntil.onNext,这里就通过frc进行了dispose

Bug:

一个RxLifecycle的小问题。

在compose的时候
1. 如果until事件是FragmentEvent.DESTROY_VIEW,fragment的请求在onDestoryView之后发出,会出现问题。原因:在onDestoryView的时候,因为请求还没有发出,队列是空的,所以BehaviorSubject$BehaviorDisposable.emitNext不会调用到,而之后,DESTROY_VIEW事件被后面的DESTORY和DETACH事件依次冲掉,所以请求返回时由于事件不是DESTROY_VIEW,所以请求不会被取消,最后请求的回调依然被调用
2. 如果until事件是FragmentEvent.DETACH,那么在onDestoryView和onDetach之间返回了请求结果的话也会发生问题。

综合考虑,把until事件设置成DESTROY_VIEW,然后把RxFragment里的onDestory和onDetach中调用的onNext去掉比较好。

展开阅读全文

没有更多推荐了,返回首页