RxAndroid 2.0 學習筆記

Rxjava 2.x正式版出來已經快兩個月了。在之前的項目中也在使用Rx。但卻一直沒有時間對整個的知識進行梳理,恰好今天抽出時間,也系統的再學習一遍RxJava/RxAndroid


RxJava的使用

一、觀察者/被觀察者

1、前奏:
在觀察者之前就要先提下backpressure這個概念。簡單來說,backpressure是在異步場景中,被觀察者發送事件速度遠快于觀察者的處理速度時,告訴被觀察者降低發送速度的策略。

2、在2.0中有以下幾種觀察者

  • Observable/Observer
  • Flowable/Subscriber
  • Single/SingleObserver
  • Completable/CompletableObserver
  • Maybe/MaybeObserver

依次的來看一下:

Observable

Observable
.just(1, 2, 3)
.subscribe(new Observer < Integer > () {
@Override public void onSubscribe(Disposable d) {}
@Override public void onNext(Integer value) {}
@Override public void onError(Throwable e) {}
@Override public void onComplete() {}
});

這里要提的就是onSubscribe(Disposable d),disposable用于取消訂閱。
就用簡單的just這個操作符來分析一下。

@SuppressWarnings("unchecked")
@SchedulerSupport(SchedulerSupport.NONE) 
public static < T > Observable < T > just(T item1, T item2, T item3, T item4) {
    ObjectHelper.requireNonNull(item1, "The first item is null");
    ObjectHelper.requireNonNull(item2, "The second item is null");
    ObjectHelper.requireNonNull(item3, "The third item is null");
    ObjectHelper.requireNonNull(item4, "The fourth item is null");

    return fromArray(item1, item2, item3, item4);
}
@SchedulerSupport(SchedulerSupport.NONE) 
public static < T > Observable < T > fromArray(T...items) {
    ObjectHelper.requireNonNull(items, "items is null");
    if (items.length == 0) {
        return empty();
    } else if (items.length == 1) {
        return just(items[0]);
    }
    return RxJavaPlugins.onAssembly(new ObservableFromArray < T > (items));
}
@Override 
public void subscribeActual(Observer < ?super T > s) {
    FromArrayDisposable < T > d = new FromArrayDisposable < T > (s, array);
    s.onSubscribe(d);
    if (d.fusionMode) {
        return;
    }
    d.run();
}

@Override 
public void dispose() {
    disposed = true;
}

@Override 
public boolean isDisposed() {
    return disposed;
}

void run() {
    T[] a = array;
    int n = a.length;
    for (int i = 0; i < n && !isDisposed(); i++) {
        T value = a[i];
        if (value == null) {
            actual.onError(new NullPointerException("The " + i + "th element is null"));
            return;
        }
        actual.onNext(value);
    }
    if (!isDisposed()) {
        actual.onComplete();
    }
}

just實際調用了fromArray方法,中創建了ObservableFromArray的實例,在這個實例中實現了Observable這個接口,在調用subscribe方法進行綁定之后,首先調用了subscribeActual方法,onSubscribe就會回調。

在取消綁定是我們可以將Disposable添加到CompositeDisposable中或者直接調用Disposable的dispose() 方法在流的任意位置取消。

此外, 為了簡化代碼,我使用了Consumer作為觀察者(可以當成1.0時候的Action1 、ActionX)subscribe的返回值就是一個Disposable (subscribe 的返回值根據傳入的參數不同,也有不同)我把這個對象添加到CompositeDisposable,并在中途取消,但發射器仍然會把所有的數據全都發射完。因為LambdaSubscriber(也就是傳入Consumer 所構造的觀察者)的disposeisDispose 略有不同,并不是簡簡單單的true/false, 說實話,我沒看懂Consumer的這兩個方法干了什么...........尷尬

LambdaSubscriber 瞅瞅

@Override
public void dispose() { 
cancel();
}

@Override
public boolean isDisposed() {  
  return get() == SubscriptionHelper.CANCELLED;
}

Flowable

是2.0之后用的最多的觀察者了,他與上一個的區別在于支持背壓,也就是說,下游會知道上游有多少數據,所以他Subscriber會是這樣

Flowable
.just(1, 2, 3, 4)
.subscribe(new Subscriber < Integer > () {
@Override public void onSubscribe(Subscription s) {
  s.request(Long.MAX_VALUE);
}
@Override public void onNext(Integer integer) {}
@Override public void onError(Throwable t) {}
@Override public void onComplete() {}
});

onSubscribe 這個回調傳出了一個Subscription, 我們要指定他傳出數據的大小, 調用他的request() 方法。如沒有要求可以傳入一個Long的最大數值Long.MAX_VALUE
要說明一下,request這個方法若不調用,下游的onNext與OnComplete都不會調用;若你寫的數量小于,只會傳你的個數,但是不會調用onComplete方法,可以看下FlowableFromArrayslowPath方法

@Override void slowPath(long r) {
    long e = 0;
    T[] arr = array;
    int f = arr.length;
    int i = index;
    Subscriber < ?super T > a = actual;
    for (;;) {
        while (e != r && i != f) {
            if (cancelled) {
                return;
            }
            T t = arr[i];
            if (t == null) {
                a.onError(new NullPointerException("array element is null"));
                return;
            } else {
                a.onNext(t);
            }
            e++;
            i++;
        }
        if (i == f) {
            if (!cancelled) {
                a.onComplete();
            }
            return;
        }
        r = get();
        if (e == r) {
            index = i;
            r = addAndGet( - e);
            if (r == 0L) {
                return;
            }
            e = 0L;
        }
    }
}
}

需要if (i == f) f 是這個數據的大小,i是當前發送數據的個數,所以不會調用onComplete

休息一下

這是幾種被觀察者實現的接口

  • Observable 接口 ObservableSource
  • Flowable 接口 Publisher
  • Single 接口 SingleSource
  • Completable 接口 CompletableSource
  • Maybe 接口 MaybeSource

梳理完了兩個被觀察者,發現Flowable支持背壓,父類是Publisher;Observable不支持背壓,父類是ObservableSource,他們的實現方式,與其的操作符,到最后的觀察者,都有些不同,他們是完全獨立開的。各自之間也互不影響。

Single

單值相應的模式: 就是只有一個值唄?

Completable

表示沒有任何值但僅指示完成或異常的延遲計算。

Maybe

maybe 可以當成上面兩個的合體吧!

后面的三種,就不細掰了,我就是這么不求甚解。

二、操作符

操作符基本就沒有改變,但還是會發現,我擦,from沒了,可以使用fromIterable
之前的actionx 也替換了Action \ Consumer \ BiConsumer
Func也跟action一樣, 名字改變了Function

感覺這樣是正經Rx了。

三、線程切換

當然現場切換沒有發生改變,用法還是一樣,但是之前沒有看過源碼,不知道怎樣神奇的把線程切換了,難道是來自東方的神秘力量。趁著還有時間,擼一下代碼。
在調用subscribeOn(Schedulers.io())之后,會創建ObservableSubscribeOn

parent.setDisposable(scheduler.scheduleDirect(new Runnable() {
@Override
public void run() {
        source.subscribe(parent);
    }
}
));

在這個過程中,會把source也就是ObservableSource在線程中訂閱,同時也把把傳入的Observer變成SubscribeOnObserver。若指定的是io線程,可以在IoScheduler中看見對線程的管理
在調用observeOn(AndroidSchedulers.mainThread())時,會產生一個ObservableObserveOn,同時還會把Observer變成ObserveOnObserver,可以發現在HandlerScheduler,在ui線程調用了ObserveOnObserver的run方法

四、Rxjava的數據傳遞

Rxjava是我在工作這幾個月最喜歡的框架,沒有之一。完全解決了我這個有潔癖的人在打代碼時的玻璃心。
雖然重復造輪輪子是沒有必要的(我也造不出來),但是為了全面的了解Rxjava,我也準備簡單的實現一下,數據在每個操作符之中傳輸的整個過程。

在實現之前先猜想一下大概的過程吧:
我的需求是在一個static方法中產生一個數值,并且通過一層層的接口傳遞下去,下面的操作符的人參是上一個的返回值,最后輸出,我就模仿著Rx的 Maybe 的名字實現吧。

  • 首先我要一直‘點’下去的話Maybe 一定要返回自己
  • 接口要一層層的傳進去,這樣的話就可以在發射數據時,發原始數據傳入這個一堆的接口,然后每個接口計算自己的實現。
  • 最后返回結果

之后就是仿造源碼完成這段需求了,當然這些方法也都簡單寫了,就是為了弄清楚思路:

1、創建一個MaybeSource,我們的Maybe 和 各個操作符都會實現它。

public interface MaybeSource {
     void subscribe(MaybeObserver observer);
}

2、創建一個MaybeObserver, 這就是最后綁定的時候的接口

public interface MaybeObserver {
    void onSuccess(int value);
}

3、創建Function, 這個在操作符中用于實現

public interface Function {
    int apply(int t);
}

4、當然少不了Maybe, 這里就實現just和map兩個方法吧

public abstract class Maybe implements MaybeSource {
    public static Maybe just(int item) {
        return new MaybeJust(item);
    }

    public final Maybe map(Function mapper) {
        return new MaybeMap(this, mapper);
    }
}

5、just實際返回的對象是MaybeJust,他的父類是Maybe

public class MaybeJust extends Maybe {
    final int value;

    public MaybeJust(int value) {
        this.value = value;
    }

    @Override
    public void subscribe(MaybeObserver observer) {
        observer.onSuccess(value);
    }
}

6、map實際返回的對象是MaybeMap,他的父類是Maybe

public class MaybeMap extends Maybe {
    final Function mapper;
    final MaybeSource source;

    public MaybeMap(MaybeSource source, Function mapper) {
        this.source = source;
        this.mapper = mapper;
    }

    @Override
    public void subscribe(MaybeObserver observer) {
        source.subscribe(new MapMaybeObserver(observer, mapper));
    }

    static final class MapMaybeObserver implements MaybeObserver {
        final MaybeObserver actual;

        final Function mapper;

        MapMaybeObserver(MaybeObserver actual, Function mapper) {
            this.actual = actual;
            this.mapper = mapper;
        }

        @Override
        public void onSuccess(int value) {
            this.actual.onSuccess(this.mapper.apply(value));
        }
    }
}

7、在main中可以這么運行

Maybe
.just(1)
.map(new Function() {

    @Override
    public int apply(int t) {
        return t + 1;
    }
}).map(new Function() {

    @Override
    public int apply(int t) {
        return t * 4;
    }
}).subscribe(new MaybeObserver() {

    @Override
    public void onSuccess(int value) {
        System.out.println(value);
    }
});

8、運行結果,傳入1,先+1, 在 * 4,最后結果應該是8

Paste_Image.png

得到了期望的結果


RxJava 2.0 + Retrofit 2 .0

之前做過一個項目,沒用什么架構,也沒什么封裝。但對我幫助最大的是,之前是不能接受這樣的代碼的,感覺看上去腦袋都大了。但看習慣了, 也就習慣了。
但平時自己弄個小項目還是使用mvp,自己的潔癖可能更加強烈一點

在Retrofit 中選擇了Flowable作為返回值,支持背壓,在2.0之后應該最為常用

@GET("/")  
Flowable<ResponseBody> getText();

在RxJava 2.0 中使用CompositeDisposable做解除綁定的操作, Consumer 回調中使用了三個Consumer,作為成功、失敗、完成的回調

    public <T> void addSubscription(Flowable flowable,
        final RxSubscriber<T> subscriber) {
        if (mCompositeDisposable == null) {
            mCompositeDisposable = new CompositeDisposable();
        }

        if (subscriber == null) {
            Log.e(TAG, "rx callback is null");

            return;
        }

        Disposable disposable = flowable.subscribeOn(Schedulers.io())
                                        .observeOn(AndroidSchedulers.mainThread())
                                        .subscribe(new Consumer<T>() {
                    @Override
                    public void accept(T o) throws Exception {
                        subscriber.onNext(o);
                    }
                },
                new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable)
                        throws Exception {
                        subscriber.onError(throwable);
                    }
                },
                new Action() {
                    @Override
                    public void run() throws Exception {
                        subscriber.onComplete();
                    }
                });

此外,之前的項目后臺接口也是奇葩,同一個人寫的接口,接口的返回格式更是多種多樣,還不改,沒辦法,客戶端只能將就著服務端,誰叫我們是新來的呢。遇到這種問題,就不直接轉成對象格式了,先轉成ResponseBody得到Body,再拿出string來。
okhttp中response的body對象就是這個ResponseBody,他的string() 方法就可以獲得整個body,然后再做json解析吧

Paste_Image.png
Paste_Image.png
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,646評論 6 533
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,595評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,560評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,035評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,814評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,224評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,301評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,444評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,988評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,804評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,998評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,544評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,237評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,665評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,927評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,706評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,993評論 2 374

推薦閱讀更多精彩內容