rxjava的disposable

rxjava+retrofit處理網(wǎng)絡(luò)請求

在使用rxjava+retrofit處理網(wǎng)絡(luò)請求的時候,一般會采用對觀察者進行封裝扔水,實現(xiàn)代碼復(fù)用和拓展痛侍。一種可行的封裝如下:

  • 基類observer
public abstract class BaseObserver<T> implements Observer<T> {

    protected String errMsg = "";
    protected Disposable disposable;

    @Override
    public void onSubscribe(Disposable d) {
        disposable = d;
    }

    @Override
    public void onNext(T t) {
    }

    @Override
    public void onError(Throwable e) {
        LogUtils.d("Subscriber onError", e.getMessage());
        if (!NetworkUtils.isConnected()) {
            errMsg = "網(wǎng)絡(luò)連接出錯,";
        } else if (e instanceof APIException) {
            APIException exception = (APIException) e;
            errMsg = exception.getMessage() + ", ";
        } else if (e instanceof HttpException) {
            errMsg = "網(wǎng)絡(luò)請求出錯,";
        } else if (e instanceof IOException) {
            errMsg = "網(wǎng)絡(luò)出錯,";
        }

        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }

    @Override
    public void onComplete() {
        if (disposable != null && !disposable.isDisposed()) {
            disposable.dispose();
        }
    }
}

  • 封裝請求(登錄為例) 這里userService是retrofit接口類
    /**
     * 登錄
     * @param phone    賬號
     * @param password 密碼
     * @param observer 觀察者
     */
    public void login(String phone, String password, BaseObserver<ResponseBean<UidBean>> observer) {
//        userService.login(new RequestUserBean(phone, EncryptUtils.encryptMD5ToString(password)))
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(observer);
    }

  • 方法調(diào)用
     APIUser.getInstance().login(phone, password, new BaseObserver<ResponseBean<UidBean>>() {
                @Override
                public void onSubscribe(Disposable d) {
                    addDisposable(d);
                }

                @Override
                public void onNext(ResponseBean<UidBean> responseBean) {
                   ToastUtils.showShort("登錄成功");
                }

                @Override
                public void onError(Throwable e) {
                    super.onError(e);
                    ToastUtils.showShort(errMsg+"登錄失敗");
                }
            });

網(wǎng)上大家對rxjava+retrofit好的封裝很多,我這里不再贅述魔市。

關(guān)于disposable

rxjava雖然好用主届,但是總所周知,容易遭層內(nèi)存泄漏待德。也就說在訂閱了事件后沒有及時取閱岂膳,導(dǎo)致在activity或者fragment銷毀后仍然占用著內(nèi)存,無法釋放磅网。而disposable便是這個訂閱事件谈截,可以用來取消訂閱。但是在什么時候取消訂閱呢涧偷?我知道有兩種方式:

    1. 使用CompositeDisposable

看源碼簸喂,CompositeDisposable的介紹很簡單

A disposable container that can hold onto multiple other disposables and offers O(1) add and removal complexity.

一個disposable的容器,可以容納多個disposable燎潮,添加和去除的復(fù)雜度為O(1)喻鳄。
這里需要注意的是在該類的addAll方法有這么一句注釋

Atomically adds the given array of Disposables to the container or disposes them all if the container has been disposed

也就是說,如果這個CompositeDisposable容器已經(jīng)是處于dispose的狀態(tài)确封,那么所有加進來的disposable都會被自動切斷除呵。

所以說可以創(chuàng)建一個BaseActivity再菊,用CompositeDisposable來管理訂閱事件disposable,然后在acivity銷毀的時候颜曾,調(diào)用compositeDisposable.dispose()就可以切斷所有訂閱事件纠拔,防止內(nèi)存泄漏。

    1. 在oError和onComplete后調(diào)用disposable.dispose();泛豪,也就是上面我給的例子中的方法稠诲。

查看源碼,ObservableCreate的靜態(tài)類CreateEmitter就是這種方式實現(xiàn)的诡曙。同時也可以看到臀叙,onError和onComplete不可以同時調(diào)用的原因:每次掉用過onError或onComplete其中一個方法后,就會掉用dispose()方法价卤,此時訂閱取消劝萤,自然也就不能掉用另一個方法了

static final class CreateEmitter<T>
   extends AtomicReference<Disposable>
   implements ObservableEmitter<T>, Disposable {


       private static final long serialVersionUID = -3434801548987643227L;

       final Observer<? super T> observer;

       CreateEmitter(Observer<? super T> observer) {
           this.observer = observer;
       }

       @Override
       public void onNext(T t) {
           if (t == null) {
               onError(new NullPointerException("onNext called with null. Null values are generally not allowed in 2.x operators and sources."));
               return;
           }
           if (!isDisposed()) {
               observer.onNext(t);
           }
       }

       @Override
       public void onError(Throwable t) {
           if (t == null) {
               t = new NullPointerException("onError called with null. Null values are generally not allowed in 2.x operators and sources.");
           }
           if (!isDisposed()) {
               try {
                   observer.onError(t);
               } finally {
                   dispose();
               }
           } else {
               RxJavaPlugins.onError(t);
           }
       }

       @Override
       public void onComplete() {
           if (!isDisposed()) {
               try {
                   observer.onComplete();
               } finally {
                   dispose();
               }
           }
       }

       @Override
       public void setDisposable(Disposable d) {
           DisposableHelper.set(this, d);
       }

       @Override
       public void setCancellable(Cancellable c) {
           setDisposable(new CancellableDisposable(c));
       }

       @Override
       public ObservableEmitter<T> serialize() {
           return new SerializedEmitter<T>(this);
       }

       @Override
       public void dispose() {
           DisposableHelper.dispose(this);
       }

       @Override
       public boolean isDisposed() {
           return DisposableHelper.isDisposed(get());
       }
   }

除此之外,在github發(fā)現(xiàn)一個開源庫RxLifecyclee慎璧,粗略了解發(fā)現(xiàn)他實現(xiàn)的原理是綁定acvitvity是生命周期稳其,在onStart中綁定就在onStop中解綁,其他onResume炸卑,onCreate同理既鞠。這個和第一種方式似乎又差不多,只不過第一種方式簡單盖文,只在ondestory的時候銷毀所有事件嘱蛋。

所以那兩種方法哪種更好,我也不是很清楚五续。等到踩到什么坑了可能就知道了洒敏。
如果某位大佬知道,希望不吝指教疙驾。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凶伙,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子它碎,更是在濱河造成了極大的恐慌函荣,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,978評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扳肛,死亡現(xiàn)場離奇詭異傻挂,居然都是意外死亡,警方通過查閱死者的電腦和手機挖息,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評論 2 384
  • 文/潘曉璐 我一進店門金拒,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人套腹,你說我怎么就攤上這事绪抛∽收。” “怎么了?”我有些...
    開封第一講書人閱讀 156,623評論 0 345
  • 文/不壞的土叔 我叫張陵幢码,是天一觀的道長笤休。 經(jīng)常有香客問我,道長蛤育,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,324評論 1 282
  • 正文 為了忘掉前任葫松,我火速辦了婚禮瓦糕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘腋么。我一直安慰自己咕娄,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 65,390評論 5 384
  • 文/花漫 我一把揭開白布珊擂。 她就那樣靜靜地躺著圣勒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪摧扇。 梳的紋絲不亂的頭發(fā)上圣贸,一...
    開封第一講書人閱讀 49,741評論 1 289
  • 那天,我揣著相機與錄音扛稽,去河邊找鬼吁峻。 笑死,一個胖子當(dāng)著我的面吹牛在张,可吹牛的內(nèi)容都是我干的用含。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼帮匾,長吁一口氣:“原來是場噩夢啊……” “哼啄骇!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起瘟斜,我...
    開封第一講書人閱讀 37,655評論 0 266
  • 序言:老撾萬榮一對情侶失蹤缸夹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后螺句,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體明未,經(jīng)...
    沈念sama閱讀 44,104評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年壹蔓,在試婚紗的時候發(fā)現(xiàn)自己被綠了趟妥。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,569評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡佣蓉,死狀恐怖披摄,靈堂內(nèi)的尸體忽然破棺而出亲雪,到底是詐尸還是另有隱情,我是刑警寧澤疚膊,帶...
    沈念sama閱讀 34,254評論 4 328
  • 正文 年R本政府宣布义辕,位于F島的核電站,受9級特大地震影響寓盗,放射性物質(zhì)發(fā)生泄漏灌砖。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,834評論 3 312
  • 文/蒙蒙 一傀蚌、第九天 我趴在偏房一處隱蔽的房頂上張望基显。 院中可真熱鬧,春花似錦善炫、人聲如沸撩幽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,725評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽窜醉。三九已至,卻和暖如春艺谆,著一層夾襖步出監(jiān)牢的瞬間榨惰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,950評論 1 264
  • 我被黑心中介騙來泰國打工静汤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留读串,地道東北人。 一個月前我還...
    沈念sama閱讀 46,260評論 2 360
  • 正文 我出身青樓撒妈,卻偏偏與公主長得像恢暖,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子狰右,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,446評論 2 348