RxJava內存泄漏——(2)AutoDispose解決RxJava內存泄漏

概述

本文的主要內容如下:

  • AutoDispose的基礎使用
  • AutoDispose的基本原理
  • AutoDispose和RxLifecycle的區別
  • 如何添加到目前的Android項目中(以MVP架構爲例)
  • 小結

基礎使用

官方文檔永遠是最好的說明書:

AutoDispose: Automatic binding+disposal of RxJava 2 streams.

1、添加依賴

 implementation 'com.uber.autodispose:autodispose-android-archcomponents:1.0.0-RC2'

2、在你的代碼中直接使用,比如:

//在Activity中使用
myObservable
    .map(...)
    .subscribeOn(...)
    .observeOn(...)
    .as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this))  
    .subscribe(s -> ...);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

通過給Observable(或者Single、Completable、Flowable等響應式數據類型,本文皆以Observable爲例)添加這行代碼:

as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(lifecycleOwner))

該Observable就會在Activity的onDestory()生命週期時,自動解除訂閱,以防止因生命週期組件的生命週期而導致的RxJava內存泄漏事件。

看到這裏,對比RxLifecycle的代碼使用方式:

myObservable
    .compose(RxLifecycle.bind(lifecycle))
    .subscribe();
  • 1
  • 2
  • 3

似乎都差不多,都是通過添加一行代碼實現RxJava事件流與組件生命週期的綁定,那麼替換RxLifecycle的意義何在?

先按住這個問題不表,我先簡單闡述一下AutoDispose的原理。

基本原理

直接長篇大論針對源碼逐行分析,無疑是愚蠢的——我無法保證讀者能夠耐住性子看完枯燥無味的源碼分析,然後興致勃勃去嘗試這個庫,這與我初衷不符。

拋開細節,直接闡述其設計思想。

首先前提是,您需要對Google最新的Lifecycle組件有一定的瞭解,在這裏我列出之前寫的博客以供參考:

Android官方架構組件:Lifecycle詳解&原理分析

同時,如果您對RxLifecycle的原理也掌握的話,相信對於接下來的內容,閱讀起來會更加輕鬆:

解決RxJava內存泄漏(前篇):RxLifecycle詳解及原理分析

我們首先思考三個問題:

as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this))

  • this是一個什麼樣的參數?
  • 如何實現生命週期的綁定?
  • as方法執行後生成了一個什麼?

1、我傳了一個什麼參數?

這個this直觀的講,就是Activity本身,當然它也可以是Fragment,這個參數對象只有一個要求,就是必須實現LifecycleOwner接口。

LifecycleOwner接口是Google Android官方架構組件:Lifecycle的一個重要組件,在v7包中,FragmentActivity和Fragment都實現了這個接口,實現了這個接口的對象都擁有生命週期(Lifecycle)。

這意味着,不僅是AppCompatActiviy(FragmentActivity的子類)和Fragment,只要是實現了LifecycleOwner的類,都可以作爲參數傳給AutoDispose,用以控制Observable和組件生命週期的綁定。

2、如何實現生命週期的綁定

參考RxLifecycle的原理:

1.在Activity中,定義一個Observable(Subject),在不同的生命週期發射不同的事件;
2.通過compose操作符(內部實際上還是依賴takeUntil操作符),定義了上游數據,當其接收到Subject的特定事件時,取消訂閱;
3.Subject的特定事件並非是ActivityEvent,而是簡單的boolean,它已經內部通過combineLast操作符進行了對應的轉化。

AutoDispose獲取了Activity(LifecycleOwner)對象,並定義了一個新的Observable,在Activity的不同生命週期中,發射對應的事件。

和RxLifecycle很類似的是,AutoDispose在被訂閱時,獲取到Activity當前的生命週期,並找到對應需要結束訂閱的生命週期事件:

  private static final Function<Lifecycle.Event, Lifecycle.Event> DEFAULT_CORRESPONDING_EVENTS =
      new Function<Lifecycle.Event, Lifecycle.Event>() {
        @Override public Lifecycle.Event apply(Lifecycle.Event lastEvent) throws Exception {
          switch (lastEvent) {
            case ON_CREATE:
              return Lifecycle.Event.ON_DESTROY;//比如我在onCreate到onStart之間訂閱,我會在ON_DESTROY時結束訂閱
            case ON_START:
              return Lifecycle.Event.ON_STOP;
            case ON_RESUME:
              return Lifecycle.Event.ON_PAUSE;
            case ON_PAUSE:
              return Lifecycle.Event.ON_STOP;
            case ON_STOP://如果是onPause之後訂閱,會拋出異常
            case ON_DESTROY:
            default:
              throw new LifecycleEndedException("Lifecycle has ended! Last event was " + lastEvent);
          }
        }
      };
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

也就是說,在我們的ObservableA訂閱時,就已經知道了自己在Activity的哪個生命週期讓AutoDispose內部自定義的ObservableB自動發射事件,ObservableA監聽到這個事件時且未dispose,解除訂閱避免內存泄漏。

畢竟內存泄漏是少數,更大的可能是ObservableA早就執行完任務dispose了,因此ObservableB實際上就是一個Maybe,類似於

ObservableA.takeUntil( Maybe< true > )

下面爲核心代碼:

 public static <E> Maybe<LifecycleEndNotification> resolveScopeFromLifecycle(
      Observable<E> lifecycle,
      final E endEvent) {
    return lifecycle.skip(1)
        .map(new Function<E, Boolean>() {
          @Override public Boolean apply(E e) throws Exception {
            return e.equals(endEvent);//是否是要解除訂閱的生命週期事件
          }
        })
        .filter(IDENTITY_BOOLEAN_PREDICATE)//篩選爲true的數據,即篩選解除訂閱的生命週期事件
        .map(TRANSFORM_TO_END)//轉換爲LifecycleEndNotification.INSTANCE,這個枚舉只用來通知解除訂閱
        .firstElement();//返回值爲Maybe,因爲可能不到對應生命週期,ObservableA就已經完成任務,onComplete() -> dispose了
  }

  private static final Function<Object, LifecycleEndNotification> TRANSFORM_TO_END =
      new Function<Object, LifecycleEndNotification>() {
        @Override public LifecycleEndNotification apply(Object o) throws Exception {
          return LifecycleEndNotification.INSTANCE;
        }
      };

  public enum LifecycleEndNotification {
    INSTANCE
  }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

3、as方法執行後生成了一個什麼?

as方法內部生成了一個AutoDisposeConverter對象,類似於compose,不同的是,Observable通過compose生成的對象還是Observable,但as方法生成的則是一個新的對象:

public final <R> R as(@NonNull ObservableConverter<T, ? extends R> converter)
  • 1

實際上,拋開復雜的細節,AutoDispose最終將原來的Observable,生成了一個新的AutoDisposeObservable對象, 在執行訂閱時,也生成了一個新的AutoDisposingObserverImpl對象,篇幅所限,不再細述。

AutoDispose和RxLifecycle的區別

從上面的原理來講,似乎AutoDispose和RxLifecycle兩者沒什麼區別,原理都極爲相似。

事實確實如此,因爲AutoDispose本身就是很大一部分借鑑了RxLifecycle,同時,RxLifecycle的作者Daniel Lew 對於 AutoDispose的開發也有很多幫助:

以下摘錄於AutoDispose的官方文檔:

Special thanks go to Dan Lew (creator of RxLifecycle), who helped pioneer this area for RxJava in android and humored many of the discussions around lifecycle handling over the past couple years that we’ve learned from. Much of the internal scope resolution mechanics of
AutoDispose are inspired by RxLifecycle.

那麼,究竟是什麼原因,讓RxLifecycle的作者Daniel Lew 在他自己的文章中,羅列出RxLifecycle在開發中的窘境,並同時強烈推薦使用AutoDispose呢?

I’m going to keep maintaining RxLifecycle because people are still using it (including Trello), but in the long term I’m pulling away from it. For those still wanting this sort of library, I would suggest people look into AutoDispose, since I think it is better architecturally than RxLifecycle.
(我將會繼續維護RxLifecycle因爲很多人都在使用它,但是我會漸漸放棄這個庫,我建議大家可以參考AutoDispose,因爲我認爲它的設計更加優秀 )

壓倒性優勢?

我們來看看RxLifecycle的侷限性:

1、需要繼承父類(RxActivity / RxFragment等)

對於設計來講,【組合】的靈活度大多數情況都優於【繼承】,而RxLifecycle在父類中聲明瞭一個PublishSubject,用來發射生命週期事件,這是導致其侷限性的原因之一。

2、如何處處綁定生命週期?

最簡單的例子,我的RecyclerView的Adapter中訂閱了Observable,亦或者,在MVP的架構或者MVVM架構中,我的presenter或者我的viewModel無法直接獲取RxActivity的引用(作爲View層,更應該抽象爲一個接口與Presenter進行交互)。

這意味着,想要進行Observable的生命週期綁定,在RecyclerView的Adapter中,我必須要通過將Activity作爲依賴,注入到Adapter中:

new ListAdapter(RxActivity activity);
  • 1

而對於Presenter,我需要對View抽象接口進行instanceof 的判斷:

if (view instanceof RxActivity) {
   return bindToLifecycle((RxActivity) view);
}
  • 1
  • 2
  • 3

當然還有一些其他的情況,請參考原作者的文章:

Why Not RxLifecycle?

如何添加到目前的Android項目中(以MVP架構爲例)

AutoDispose正常直接在項目中使用沒有什麼問題,比如:

//在Activity中使用
myObservable
    .as(AutoDispose.autoDisposable(AndroidLifecycleScopeProvider.from(this))  
    .subscribe(s -> ...);
  • 1
  • 2
  • 3
  • 4

但是,在實際的生產環境中,我們更希望有一個良好的方式,能夠達到統一管理Observable綁定生命週期的效果,在此筆者以MVP的架構爲例,拋磚引玉,希望能夠獲得大家的意見和建議。

1、封裝Util類

首先封裝Util類,將職責賦予RxLifecycleUtils:

public class RxLifecycleUtils {

    private RxLifecycleUtils() {
        throw new IllegalStateException("Can't instance the RxLifecycleUtils");
    }

    public static <T> AutoDisposeConverter<T> bindLifecycle(LifecycleOwner lifecycleOwner) {
        return AutoDispose.autoDisposable(
                AndroidLifecycleScopeProvider.from(lifecycleOwner)
        );
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

2、面向LifecycleOwner接口

現在,只要持有LifecycleOwner對象,Observable都可以通過RxLifecycleUtils.bindLifecycle(LifecycleOwner)進行綁定。

比如我們在BaseActivity/BaseFragment中添加代碼:

public abstract class BaseActivity extends AppCompatActivity implements IActivity {
    //...忽略其他細節
    protected <T> AutoDisposeConverter<T> bindLifecycle() {
        return RxLifecycleUtils.bindLifecycle(this);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

這樣,在任何BaseActivity的實現類中,我們都可以通過下述代碼實現Observable的生命週期綁定:

myObservable
    .as(bindLifecycle())  
    .subscribe(s -> ...);
  • 1
  • 2
  • 3

但是這樣的行爲意義不大,我們更希望在Presenter中也能夠像上述代碼一樣達到Observable生命週期的綁定,但是不持有Activity的對象的同時,避免RxLifecycle中尷尬的instanceof判斷。

可行嗎,可行。

3、使用Google官方Lifecycle組件

首先讓我們的IPresenter接口實現LifecycleObserver接口:

public interface IPresenter extends LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
    void onCreate(@NotNull LifecycleOwner owner);

    @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
    void onDestroy(@NotNull LifecycleOwner owner);

    @OnLifecycleEvent(Lifecycle.Event.ON_ANY)
    void onLifecycleChanged(@NotNull LifecycleOwner owner,
                            @NotNull Lifecycle.Event event);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

然後在BasePresenter中管理LifecycleOwner:

public class BasePresenter<V extends IView, M extends IModel> implements IPresenter {

    @Getter
    protected V mRootView;

    @Getter
    protected M mModel;

    private LifecycleOwner lifecycleOwner;

    public BasePresenter(V rootView, M model) {
        this.mRootView = rootView;
        this.mModel = model;
    }

    protected <T> AutoDisposeConverter<T> bindLifecycle() {
        if (null == lifecycleOwner)
            throw new NullPointerException("lifecycleOwner == null");
        return RxLifecycleUtils.bindLifecycle(lifecycleOwner);

    public void onCreate(@NotNull LifecycleOwner owner) {
        this.lifecycleOwner = owner;
    }

    public void onDestroy(@NotNull LifecycleOwner owner) {
            if (mModel != null) {
                mModel.onDestroy();
                this.mModel = null;
            }
            this.mRootView = null;
        }
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

最後在Activity中添加Presenter爲觀察者,觀察Activity的生命週期

public abstract class BaseActivity<P extends IPresenter> extends AppCompatActivity implements IActivity {

    @Inject
    protected P presenter;

        @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getLayoutId());
        //...忽略其他代碼,比如ButterKnife、Dagger2等
        lifecycle.addObserver(presenter);
    }       

    protected <T> AutoDisposeConverter<T> bindLifecycle() {
        return RxLifecycleUtils.bindLifecycle(this);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

這樣,我們即使在Presenter中,也能任意使用myObservable.as(bindLifecycle()) 方法了,和RxLifecycle相比,更加靈活。

篇幅所限,僅以最簡單的設計思路進行闡述,更多情況的使用請在項目中自行拓展。

更詳細的使用,請參考我的個人MVP架構:MvpArchitecture-Android

2018.9追加

時隔數月,我的個人MVP架構:MvpArchitecture-Android 已經無法滿足我個人開發的需求,於我而言它更像是一個demo,因此我停止了對它的維護。

相比前者,我更喜歡MVVM架構中AutoDispose的這次實踐,它更趨近我理想中的設計,更加ReactiveFunctional

MVVM-Rhine:The MVVM Architecture in Android.

小結

事實上AutoDispose還有很多優秀的設計點,在源碼中得以體現(包括自己實現Observable和其Observer,以及通過代理對內部的Observable進行封裝,對原子操作類的靈活運用 等等)。

但無論是RxLifecycle,AutoDispose,亦或者是自己封裝的util類,對於項目來說,只要滿足需求,並無優劣之分,我們更希望能夠從一些他人的框架中,學習到他們設計的思想,和良好的代碼風格,便足矣。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章