Android技能樹 — Rxjava取消訂閱小結(1):自帶方式

前言:

Android技能樹系列:java

Android基礎知識算法

Android技能樹 — 動畫小結數組

Android技能樹 — View小結bash

Android技能樹 — Activity小結網絡

Android技能樹 — View事件體系小結數據結構

Android技能樹 — Android存儲路徑及IO操做小結多線程

Android技能樹 — 多進程相關小結異步

Android技能樹 — Drawable小結async

數據結構基礎知識ide

Android技能樹 — 數組,鏈表,散列表基礎小結

Android技能樹 — 樹基礎知識小結(一)

算法基礎知識

Android技能樹 — 排序算法基礎小結

Rx系列相關

Android技能樹 — RxPermission分析

Android技能樹 — Rxjava取消訂閱小結(1):自帶方式

Android技能樹 — Rxjava取消訂閱小結(2):RxLifeCycle

如今不少項目都在使用Rxjava了,對於RxJava的使用,估計都很熟悉了,可是不少人在使用RxJava的時候容易產生內存泄漏問題,好比咱們在用RxJava配合Retrofit的時候,發出請求出去,拿到數據後咱們可能會去刷新界面,可是若是這時候網絡比較差,返回比較慢,而咱們的Activity這時候關閉了,那RxJava當拿到返回的數據的時候去刷新界面就會報空指針異常了。因此咱們當Activity關閉的時候,咱們這時候若是RxJava還沒執行完,咱們應該取消訂閱。

經常使用的主要三種方式:(按照⭐️推薦從低到高來介紹)

  1. 自帶取消訂閱方式(⭐️)
  2. RxLifeCycle(⭐️⭐️)
  3. AutoDispose(⭐️⭐️⭐️)

本文主要講自帶取消訂閱方式。

1. 自帶取消訂閱方式:

在RxJava 1的時候咱們知道在你用Observable執行時候會返回一個Subscription類:

Subscription subscription = Observable.xxx("yy").subscribe(.....);
複製代碼

而後咱們只須要在咱們界面的ondestory方法中對這個對象進行取消訂閱操做就能夠:

@Override
protected void onDestroy() {

    if (subscription != null && !subscription.isUnsubscribed) {
        subscription. unsubscribe();
    }
    
    super.onDestroy();
}
複製代碼

咱們能夠看到很簡單,這樣當咱們Activity關閉的時候已經自動取消了訂閱。

而RxJava2換了方式,可是基本方法是如出一轍的,只是換成了Disposable

若是咱們使用的是Consumer,那和原來RxJava 1 是同樣的操做:

Disposable disposable = Observable.just(1).subscribe(new Consumer<Integer>() {
    @Override
    public void accept(@NonNull Integer integer) throws Exception {

    }
});

//取消訂閱
if(disposable != null && !disposable.isDisposed()){
     disposable.dispose();
}
複製代碼

可是咱們可能更多的是使用Observer等,那這時候subscrbe(observer)返回的是void,因此不能像上面同樣操做,須要下面代碼所示那樣:

private Disposable disposable;
Observable.just(1).subscribe(new Observer<Integer>() {
       @Override
       public void onSubscribe(Disposable d) {
            disposable = d;
       }

       @Override
       public void onNext(Integer integer) {}

       @Override
       public void onError(Throwable e) {}

       @Override
       public void onComplete() {}
});

//而後在須要取消訂閱的地方調用便可
if(disposable != null && !disposable.isDisposed()){
     disposable.dispose();
}


複製代碼

和RxJava 1 最大的區別主要是獲取這個取消訂閱對象的地方不一樣,Disposable是在Observer裏面的onSubscribe方法的參數拿到,而後咱們能夠定義一個臨時變量進行賦值,而後在須要取消訂閱的地方去調用便可。

可是不少人會說難道不能和RxJava 1 的方式差很少,由於不少項目已經按照RxJava 1 的方式來封裝了進行相應的取消訂閱代碼,直接換成RxJava 2 方式變化不同了,能不能變得和Rxjava 1 取消訂閱方式差很少 。答案是固然能夠。

咱們可使用DisposableObserversubscribeWith兩者結合來作的和Rxjava 1 同樣的方式來取消訂閱。

1.1 DisposableObserver

DisposableObserver 是一個抽象的 Observer, 它經過實現了 Disposable 接口容許異步取消。

/**
 * An abstract {@link Observer} that allows asynchronous cancellation by implementing Disposable.
 *
 * @param <T> the received value type
 */
public abstract class DisposableObserver<T> implements Observer<T>, Disposable {
    final AtomicReference<Disposable> s = new AtomicReference<Disposable>();

    @Override
    public final void onSubscribe(Disposable s) {
        if (DisposableHelper.setOnce(this.s, s)) {
            onStart();
        }
    }

    /**
     * Called once the single upstream Disposable is set via onSubscribe.
     */
    protected void onStart() {
    }

    @Override
    public final boolean isDisposed() {
        return s.get() == DisposableHelper.DISPOSED;
    }

    @Override
    public final void dispose() {
        DisposableHelper.dispose(s);
    }
}
複製代碼

咱們能夠看到,這個DisposableObserver即實現了Observer,又實現了Disposable接口。

PS : DisposableObserver源碼裏面有個AtomicReference,有些人也許不知道這個類,能夠初步理解爲加了鎖,方便多線程操做。具體能夠看文章Java之美[從菜鳥到高手演練]之atomic包的原理及分析

因此咱們初步代碼能夠變爲:

//好比這個是咱們的Observer
DisposableObserver observer = new DisposableObserver() {
      @Override
      public void onNext(Object o) {}
      @Override
      public void onError(Throwable e) {}
      @Override
      public void onComplete() {}
};
//把咱們的Observer對Observable進行訂閱        
Observable.just(1).subscribe(observer);

//而後在須要取消訂閱的地方對這個observer進行取消訂閱便可。
observer.dispose();
複製代碼

1.2 subscribeWith

public final <E extends Observer<? super T>> E subscribeWith(E observer) {
     subscribe(observer);
     return observer;
}
複製代碼

咱們能夠看到 subscribeWith訂閱的源碼是把Observer對象同時返回,正好配合上面的DisposableObserver:

DisposableObserver observer = Observable.just(1).subscribeWith(new DisposableObserver<Integer>() {
     @Override
     public void onNext(Integer integer) {}
     @Override
     public void onError(Throwable e) {}
     @Override
     public void onComplete() {}
});

//須要取消訂閱的地方:
observer.disposable();
複製代碼

這下是否是和咱們RxJava 1 裏面的寫法如出一轍了。

1.3 CompositeDisposable

我在看不少一些開源項目中,有些人一個界面的上會有多個訂閱(好比有多個網絡接口請求),這時候咱們須要批量取消訂閱,有些人會寫一個ArrayList,而後把這些上面咱們返回的DisposableObserver對象加入到ArrayList中,而後當咱們的界面關閉的時候,再遍歷ArrayList,把裏面的元素取出來一個個取消訂閱。實際上RxJava 2 中有替咱們考慮到這個需求。那即是CompositeDisposable類。

CompositeDisposable compositeDisposable = new CompositeDisposable();
//批量添加
compositeDisposable.add(observer1);
compositeDisposable.add(observer2);
compositeDisposable.add(observer2);
//最後一次性所有取消訂閱
compositeDisposable.dispose();
複製代碼

2. 配合MVP作封裝:

咱們以Activity爲例:

public abstract class BaseFrameActivity<P extends BasePresenter, M extends BaseModel> extends BaseActivity implements BaseView {

    public P mPresenter;
    public M mModel;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        
        //根據傳進來的第一個泛型參數實例化
        mPresenter = TUtil.getT(this, 0);
        //根據傳進來的第二個泛型參數實例化
        mModel = TUtil.getT(this, 1);
 
        if (this instanceof BaseView && mPresenter != null) {
            //實例化的presneter綁定View和model
            mPresenter.attachVM(this, mModel);
        }
        super.onCreate(savedInstanceState);
    }

    @Override
    protected void onDestroy() {

        if (mPresenter != null) {
            //當onDestory的時候調用presenter的解除View和model的綁定
            mPresenter.detachVM();
        }

        super.onDestroy();
    }
}

複製代碼

好比咱們在BaseFrameActivity裏面傳入了p 和 m 的泛型,咱們須要動態實例化,固然你也能夠用Dagger2等,好比咱們是用反射:

public class TUtil {
    public static <T> T getT(Object o, int i) {
        try {
            /**
             * getGenericSuperclass() : 得到帶有泛型的父類
             * ParameterizedType : 參數化類型,即泛型
             * getActualTypeArguments()[] : 獲取參數化類型的數組,泛型可能有多個
             */
            return ((Class<T>) ((ParameterizedType) (o.getClass()
                    .getGenericSuperclass())).getActualTypeArguments()[i])
                    .newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassCastException e) {
            e.printStackTrace();
        }
        return null;
    }

    // 得到類名className對應的Class對象
    public static Class<?> forName(String className) {
        try {
            return Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return null;
    }
}
複製代碼

咱們來看BasePresenter.java:

public abstract class BasePresenter<M, V> {
    public M mModel;
    public V mView;
    public RxManager mRxManager = new RxManager();

    public void attachVM(V v, M m) {
        this.mModel = m;
        this.mView = v;
    }

    public void detachVM() {
        mRxManager.clear();
        mView = null;
        mModel = null;
        mDialog = null;
    }

}
複製代碼

咱們把Observable等取消訂閱操做放在了RxManager裏面了:

public class RxManager {

    private CompositeDisposable compositeDisposable = new CompositeDisposable();

    public void add(Disposable d) {
        compositeDisposable.add(d);
    }

    public void clear() {
        compositeDisposable.dispose();
    }
}
複製代碼

最終好比咱們要用本身的Activity了:

  1. 只須要繼承BaseFrameActivity,而後把要實例化的P和M對象傳入:
public class SplashActivity 
      extends BaseFrameActivity<XPresenter, XModel> 
      implements XContract.View {}
複製代碼

直接就可使用mPresenter執行相關操做,而且mPresenter實例化的時候也已經實例化一個RxManager實例對象。

  1. 假設咱們用的是最原始的Observer來訂閱:
public class XPresenter extends XContract.Presenter {

    @Override
    public void getXImage() {
         mModel
             .getXImage()
             .subscribe(new Observer<SplashImgEntity>() {
                    @Override
                    public void onSubscribe(Disposable d) {                  
                        //自動就會把Disposable加入到RxManager中的CompositeDisposable 中。
                        mRxManager.add(d);
                    }

                    @Override
                    public void onNext(SplashImgEntity splashImgEntity) {

                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });

    }
}

複製代碼

而後Activity銷燬時候,會本身去幫你取消訂閱。

總結:

emmmmmm.......請多多指教。

相關文章
相關標籤/搜索