RxJava 簡介

第二章:框架介紹:

1:RxJava介紹:

是實現一個異步操作的庫,類似於異步任務或handler機制。

RxJava 其實就是提供一套異步編程的 API,這套 API 是基於觀察者模式的,而且是鏈式調用的,所以使用 RxJava 編寫的代碼的邏輯會非常簡潔。

 

RxJava 有以下三個基本的元素:

  1. 被觀察者(Observable)
  2. 觀察者(Observer)
  3. 訂閱(subscribe)

 

首先在 gradle 文件中添加依賴:

implementation 'io.reactivex.rxjava2:rxjava:2.1.4'

implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'

 

 

Demo:

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Observable observable = Observable.create(new ObservableOnSubscribe() {
            @Override
            public void subscribe(ObservableEmitter emitter) throws Exception {
                emitter.onNext("a");
                emitter.onNext("b");
                emitter.onNext("c");
                emitter.onComplete();
                Log.e("tag", "產生事件");
            }
        });

        Observer observer = new Observer() {
            @Override
            public void onSubscribe(Disposable d) {
                d.dispose();
                Log.e("tag", "取消訂閱 ");

            }

            @Override
            public void onNext(Object o) {
                Log.e("tag", "接收事件:" + o);
            }

            @Override
            public void onError(Throwable e) {

                Log.e("tag", " 數據處理出錯");
            }

            @Override
            public void onComplete() {
                Log.e("tag", "數據處理完成");

            }
        };
        observable.map(new Function() {
            @Override
            public Object apply(Object o) throws Exception {
                return o.toString();
            }
        }).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(observer);
    }


 

·被觀察者發送的事件有以下幾種,總結如下表:

 

總結如下圖:

 

1. 創建操作符

以下就是講解創建被觀察者的各種操作符。

 

1.1 create()

方法預覽:

public static <T> Observable<T> create(ObservableOnSubscribe<T> source)

有什麼用:

創建一個被觀察者

Observable observable = Observable.create(new ObservableOnSubscribe() {
    @Override
    public void subscribe(ObservableEmitter emitter) throws Exception {
        emitter.onNext("a");
        emitter.onNext("b");
        emitter.onNext("c");
        emitter.onComplete();
        Log.e("tag", "產生事件");
    }
});

上面的代碼非常簡單,創建 ObservableOnSubscribe 並重寫其 subscribe 方法,就可以通過 emitter發射器向觀察者發送事件。 

 

 

然後創建一個觀察者,來驗證這個被觀察者是否成功創建。

 

 

 

 

 Observer observer = new Observer() {
            @Override
            public void onSubscribe(Disposable d) {
//                d.dispose();
                Log.e("tag", "取消訂閱 ");

            }

            @Override
            public void onNext(Object o) {
                Log.e("tag", "接收事件:" + o);
            }

            @Override
            public void onError(Throwable e) {

                Log.e("tag", " 數據處理出錯");
            }

            @Override
            public void onComplete() {
                Log.e("tag", "數據處理完成");

            }
        };

 

 

最後用被觀察者訂閱觀察者。

observable.subscribe(observer);

 

 

觀察者與被觀察者之間的關係:

觀察者模式面向的需求是:A 對象(觀察者)對 B 對象(被觀察者)的某種變化高度敏感,需要在 B 變化的一瞬間做出反應。舉個例子,新聞裏喜聞樂見的警察抓小偷,警察需要在小偷伸手作案的時候實施抓捕。在這個例子裏,警察是觀察者,小偷是被觀察者,警察需要時刻盯着小偷的一舉一動,才能保證不會漏過任何瞬間。程序的觀察者模式和這種真正的『觀察』略有不同,觀察者不需要時刻盯着被觀察者(例如 A 不需要每過 2ms 就檢查一次 B 的狀態),而是採用註冊(Register)或者稱爲訂閱(Subscribe)的方式,告訴被觀察者:我需要你的某某狀態,你要在它變化的時候通知我。 Android 開發中一個比較典型的例子是點擊監聽器 OnClickListener 。對設置 OnClickListener 來說, View 是被觀察者, OnClickListener 是觀察者,二者通過 setOnClickListener() 方法達成訂閱關係。訂閱之後用戶點擊按鈕的瞬間,Android Framework 就會將點擊事件發送給已經註冊的 OnClickListener 。採取這樣被動的觀察方式,既省去了反覆檢索狀態的資源消耗,也能夠得到最高的反饋速度。當然,這也得益於我們可以隨意定製自己程序中的觀察者和被觀察者,而警察叔叔明顯無法要求小偷『你在作案的時候務必通知我』。

 

 

1.2 just()

方法預覽:

public static <T> Observable<T> just(T item)

......

public static <T> Observable<T> just(T item1, T item2, T item3, T item4, T item5, T item6, T item7, T item8, T item9, T item10)複製代碼

有什麼用?

創建一個被觀察者,併發送事件,發送的事件不可以超過10個以上。


Observable.just(1, 2, 3)

.subscribe(new Observer < Integer > () {

    @Override

    public void onSubscribe(Disposable d) {

        Log.d(TAG, "=================onSubscribe");

    }

 

    @Override

    public void onNext(Integer integer) {

        Log.d(TAG, "=================onNext " + integer);

    }

 

    @Override

    public void onError(Throwable e) {

        Log.d(TAG, "=================onError ");

    }

 

    @Override

    public void onComplete() {

        Log.d(TAG, "=================onComplete ");

    }

});

 

1.3 From 操作符

1.3.1 fromArray()

方法預覽:

public static <T> Observable<T> fromArray(T... items)複製代碼

有什麼用?

這個方法和 just() 類似,只不過 fromArray 可以傳入多於10個的變量,並且可以傳入一個數組。

怎麼用?

Integer array[] = {1, 2, 3, 4};

Observable.fromArray(array)

.subscribe(new Observer < Integer > () {

    @Override

    public void onSubscribe(Disposable d) {

        Log.d(TAG, "=================onSubscribe");

    }

 

    @Override

    public void onNext(Integer integer) {

        Log.d(TAG, "=================onNext " + integer);

    }

 

    @Override

    public void onError(Throwable e) {

        Log.d(TAG, "=================onError ");

    }

 

    @Override

    public void onComplete() {

        Log.d(TAG, "=================onComplete ");

    }

});

 

1.3.2 fromCallable()

方法預覽:

public static <T> Observable<T> fromCallable(Callable<? extends T> supplier)複製代碼

有什麼用?

這裏的 Callable 是 java.util.concurrent 中的 Callable,Callable 和 Runnable 的用法基本一致,只是它會返回一個結果值,這個結果值就是發給觀察者的。

怎麼用?

Observable.fromCallable(new Callable < Integer > () {

 

    @Override

    public Integer call() throws Exception {

        return 1;

    }

})

.subscribe(new Consumer < Integer > () {

    @Override

    public void accept(Integer integer) throws Exception {

        Log.d(TAG, "================accept " + integer);

    }

});

 

 

1.3.3 fromFuture()

方法預覽:

public static <T> Observable<T> fromFuture(Future<? extends T> future)複製代碼

有什麼用?

參數中的 Future 是 java.util.concurrent 中的 Future,Future 的作用是增加了 cancel() 等方法操作 Callable,它可以通過 get() 方法來獲取 Callable 返回的值。

怎麼用?


FutureTask < String > futureTask = new FutureTask < > (new Callable < String > () {

    @Override

    public String call() throws Exception {

        Log.d(TAG, "CallableDemo is Running");

        return "返回結果";

    }

});

 

Observable.fromFuture(futureTask)

    .doOnSubscribe(new Consumer < Disposable > () {

    @Override

    public void accept(Disposable disposable) throws Exception {

        futureTask.run();

    }

})

.subscribe(new Consumer < String > () {

    @Override

    public void accept(String s) throws Exception {

        Log.d(TAG, "================accept " + s);

    }

});

 

 

1.3.4 fromIterable()

方法預覽:

public static <T> Observable<T> fromIterable(Iterable<? extends T> source)複製代碼

有什麼用?

直接發送一個 List 集合數據給觀察者

怎麼用?


List<Integer> list = new ArrayList<>();

list.add(0);

list.add(1);

list.add(2);

list.add(3);

Observable.fromIterable(list)

.subscribe(new Observer < Integer > () {

    @Override

    public void onSubscribe(Disposable d) {

        Log.d(TAG, "=================onSubscribe");

    }

 

    @Override

    public void onNext(Integer integer) {

        Log.d(TAG, "=================onNext " + integer);

    }

 

    @Override

    public void onError(Throwable e) {

        Log.d(TAG, "=================onError ");

    }

 

    @Override

    public void onComplete() {

        Log.d(TAG, "=================onComplete ");

    }

});

 

1.4 defer()

方法預覽:

public static <T> Observable<T> defer(Callable<? extends ObservableSource<? extends T>> supplier)複製代碼

有什麼用?

這個方法的作用就是直到被觀察者被訂閱後纔會創建被觀察者。

怎麼用?

// i 要定義爲成員變量

Integer i = 100;

        

Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<? extends Integer>>() {

    @Override

    public ObservableSource<? extends Integer> call() throws Exception {

        return Observable.just(i);

    }

});

 

i = 200;

 

Observer observer = new Observer<Integer>() {

    @Override

    public void onSubscribe(Disposable d) {

 

    }

 

    @Override

    public void onNext(Integer integer) {

        Log.d(TAG, "================onNext " + integer);

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

};

 

observable.subscribe(observer);

 

i = 300;

 

observable.subscribe(observer);

 

 

運行結果:

05-20 20:05:01.443 26622-26622/? D/chan: ================onNext 200

================onNext 300

 

因爲 defer() 只有觀察者訂閱的時候纔會創建新的被觀察者,所以每訂閱一次就會打印一次,並且都是打印 i 最新的值

 

1.5 timer()

方法預覽:

public static Observable<Long> timer(long delay, TimeUnit unit)

......複製代碼

有什麼用?

當到指定時間後就會發送一個 0L 的值給觀察者。

怎麼用?

Observable.timer(2, TimeUnit.SECONDS)

.subscribe(new Observer < Long > () {

    @Override

    public void onSubscribe(Disposable d) {

 

    }

 

    @Override

    public void onNext(Long aLong) {

        Log.d(TAG, "===============onNext " + aLong);

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

});

 

打印結果:

05-20 20:27:48.004 27204-27259/com.example.louder.rxjavademo D/chan: ===============onNext 0

 

 

 

1.6 interval()

方法預覽:

public static Observable<Long> interval(long period, TimeUnit unit)

public static Observable<Long> interval(long initialDelay, long period, TimeUnit unit)

......複製代碼

有什麼用?

每隔一段時間就會發送一個事件,這個事件是從0開始,不斷增1的數字。

怎麼用?

Observable.interval(4, TimeUnit.SECONDS)

.subscribe(new Observer < Long > () {

    @Override

    public void onSubscribe(Disposable d) {

        Log.d(TAG, "==============onSubscribe ");

    }

 

    @Override

    public void onNext(Long aLong) {

        Log.d(TAG, "==============onNext " + aLong);

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

});

 

從時間就可以看出每隔4秒就會發出一次數字遞增1的事件。這裏說下 interval() 第三個方法的 initialDelay 參數,這個參數的意思就是 onSubscribe 回調之後,再次回調 onNext 的間隔時間。

 

 

 

 

 

 

1.7 intervalRange()

方法預覽:

public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, TimeUnit unit)

public static Observable<Long> intervalRange(long start, long count, long initialDelay, long period, TimeUnit unit, Scheduler scheduler)複製代碼

有什麼用?

可以指定發送事件的開始值和數量,其他與 interval() 的功能一樣。

怎麼用?

Observable.intervalRange(2, 5, 2, 1, TimeUnit.SECONDS)

.subscribe(new Observer < Long > () {

    @Override

    public void onSubscribe(Disposable d) {

        Log.d(TAG, "==============onSubscribe ");

    }

 

    @Override

    public void onNext(Long aLong) {

        Log.d(TAG, "==============onNext " + aLong);

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

});

打印結果:

05-21 00:03:01.672 2504-2504/com.example.louder.rxjavademo D/chan: ==============onSubscribe

05-21 00:03:03.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 2

05-21 00:03:04.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 3

05-21 00:03:05.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 4

05-21 00:03:06.673 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 5

05-21 00:03:07.674 2504-2537/com.example.louder.rxjavademo D/chan: ==============onNext 6

 

 

可以看出被觀察者的事件產生,從2開始,總共發送5次,onSubscribe 回調

與onNext回調間隔時間爲2秒,事件1秒發送一次。

 

 

1.8 range()

方法預覽:

public static Observable<Integer> range(final int start, final int count)複製代碼

有什麼用?

同時發送一定範圍的事件序列。

怎麼用?

Observable.range(2, 5)

.subscribe(new Observer < Integer > () {

    @Override

    public void onSubscribe(Disposable d) {

        Log.d(TAG, "==============onSubscribe ");

    }

 

    @Override

    public void onNext(Integer aLong) {

        Log.d(TAG, "==============onNext " + aLong);

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

});

打印結果:

05-21 00:09:17.202 2921-2921/? D/chan: ==============onSubscribe

==============onNext 2

==============onNext 3

==============onNext 4

==============onNext 5

==============onNext 6

 

 

1.9 rangeLong()

方法預覽:

public static Observable<Long> rangeLong(long start, long count)複製代碼

有什麼用?

作用與 range() 一樣,只是數據類型爲 Long

 

1.10 empty() & never() & error()

方法預覽:

public static <T> Observable<T> empty()

public static <T> Observable<T> never()

public static <T> Observable<T> error(final Throwable exception)複製代碼

有什麼用?

  1. empty() : 直接發送 onComplete() 事件
  2. never():不發送任何事件
  3. error():發送 onError() 事件


怎麼用?

Observable.empty()

.subscribe(new Observer < Object > () {

 

    @Override

    public void onSubscribe(Disposable d) {

        Log.d(TAG, "==================onSubscribe");

    }

 

    @Override

    public void onNext(Object o) {

        Log.d(TAG, "==================onNext");

    }

 

    @Override

    public void onError(Throwable e) {

        Log.d(TAG, "==================onError " + e);

    }

 

    @Override

    public void onComplete() {

        Log.d(TAG, "==================onComplete");

    }

});

 

打印結果:

 

05-26 14:06:11.881 15798-15798/com.example.rxjavademo D/chan: ==================onSubscribe

==================onComplete

 

換成 never() 的打印結果:

05-26 14:12:17.554 16805-16805/com.example.rxjavademo D/chan: ==================onSubscribe

 

 

換成 error() 的打印結果:

05-26 14:12:58.483 17817-17817/com.example.rxjavademo D/chan: ==================onSubscribe

==================onError java.lang.NullPointerException

 

 

 

2. 轉換操作符

2.1 map()

方法預覽:

public final <R> Observable<R> map(Function<? super T, ? extends R> mapper)複製代碼

有什麼用?

map 可以將被觀察者發送的數據類型轉變成其他的類型

怎麼用?

以下代碼將 Integer 類型的數據轉換成 String。

Observable.just(1, 2, 3)

.map(new Function < Integer, String > () {

    @Override

    public String apply(Integer integer) throws Exception {

        return "I'm " + integer;

    }

})

.subscribe(new Observer < String > () {

    @Override

    public void onSubscribe(Disposable d) {

        Log.e(TAG, "===================onSubscribe");

    }

 

    @Override

    public void onNext(String s) {

        Log.e(TAG, "===================onNext " + s);

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

});

打印結果:

05-21 09:16:03.490 5700-5700/com.example.rxjavademo E/chan: ===================onSubscribe

===================onNext I'm 1

===================onNext I'm 2

===================onNext I'm 3

 

 

 

2.2 flatMap()

方法預覽:

public final <R> Observable<R> flatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)

......

有什麼用?

這個方法可以將事件序列中的元素進行整合加工,返回一個新的被觀察者。

怎麼用?

flatMap() 其實與 map() 類似,但是 flatMap() 返回的是一個 Observerable。現在用一個例子來說明 flatMap() 的用法。

假設一個有一個 Person 類,這個類的定義如下:

public class Person {

 

    private String name;

    private List<Plan> planList = new ArrayList<>();

 

    public Person(String name, List<Plan> planList) {

        this.name = name;

        this.planList = planList;

    }

 

    public String getName() {

        return name;

    }

 

    public void setName(String name) {

        this.name = name;

    }

 

    public List<Plan> getPlanList() {

        return planList;

    }

 

    public void setPlanList(List<Plan> planList) {

        this.planList = planList;

    }

 

}

Person 類有一個 name 和 planList 兩個變量,分別代表的是人名和計劃清單。

Plan 類的定義如下:

 

 

 

public class Plan {

 

    private String time;

    private String content;

    private List<String> actionList = new ArrayList<>();

 

    public Plan(String time, String content) {

        this.time = time;

        this.content = content;

    }

 

    public String getTime() {

        return time;

    }

 

    public void setTime(String time) {

        this.time = time;

    }

 

    public String getContent() {

        return content;

    }

 

    public void setContent(String content) {

        this.content = content;

    }

 

    public List<String> getActionList() {

        return actionList;

    }

 

    public void setActionList(List<String> actionList) {

        this.actionList = actionList;

    }

}

現在有一個需求就是要將 Person 集合中的每個元素中的 Plan 的 action 打印出來。 首先用 map() 來實現這個需求看看:

 

Observable.fromIterable(personList)

.map(new Function < Person, List < Plan >> () {

    @Override

    public List < Plan > apply(Person person) throws Exception {

        return person.getPlanList();

    }

})

.subscribe(new Observer < List < Plan >> () {

    @Override

    public void onSubscribe(Disposable d) {

 

    }

 

    @Override

    public void onNext(List < Plan > plans) {

        for (Plan plan: plans) {

            List < String > planActionList = plan.getActionList();

            for (String action: planActionList) {

                Log.d(TAG, "==================action " + action);

            }

        }

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

});

 

可以看到 onNext() 用了嵌套 for 循環來實現,如果代碼邏輯複雜起來的話,可能需要多重循環纔可以實現。

 

 

現在看下使用 flatMap() 實現:

 

Observable.fromIterable(personList)

.flatMap(new Function < Person, ObservableSource < Plan >> () {

    @Override

    public ObservableSource < Plan > apply(Person person) {

        return Observable.fromIterable(person.getPlanList());

    }

})

.flatMap(new Function < Plan, ObservableSource < String >> () {

    @Override

    public ObservableSource < String > apply(Plan plan) throws Exception {

        return Observable.fromIterable(plan.getActionList());

    }

})

.subscribe(new Observer < String > () {

    @Override

    public void onSubscribe(Disposable d) {

 

    }

 

    @Override

    public void onNext(String s) {

        Log.d(TAG, "==================action: " + s);

    }

 

    @Override

    public void onError(Throwable e) {

 

    }

 

    @Override

    public void onComplete() {

 

    }

});

 

 

從代碼可以看出,只需要兩個 flatMap() 就可以完成需求,並且代碼邏輯非常清晰。

 

2.3 concatMap()

方法預覽:

public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper)

public final <R> Observable<R> concatMap(Function<? super T, ? extends ObservableSource<? extends R>> mapper, int prefetch)複製代碼

有什麼用?

concatMap() 和 flatMap() 基本上是一樣的,只不過 concatMap() 轉發出來的事件是有序的,而 flatMap() 是無序的。

更多詳情請看:

RxJava2 只看這一篇文章就夠了 - 掘金

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