1. 程式人生 > >RxJava介紹和使用

RxJava介紹和使用

最近開始研究RxJava,真坑爹,這個東西不好搞,可能本人的智商堪憂!終於上手了,自己總結一下。

RxJava 最早是後端用的,但是RxJava在後端上倒是不太流行,反而在Android上流行起來了!Android中UI開發需要非同步操作,使用RxJava可以隨意切換執行緒,用起來比較方便,程式碼比較清晰。

RxJava 類似 觀察者模式。有一個Observable(被觀察者,事件的發起者)和一個觀察者(Subscriber,事件的接收者)。Observable發出一系列的事件,然後Subscriber處理這些事件。

Observable 可以傳送零到多個事件;Subscriber會接收它發的每一個事件。如果Observable沒有對應的Subscriber,不會發送任何事件。

如何傳送資料

首先我們看一下Observable 是如何建立和傳送事件的。

  1. 我們需要一個Observable,用來發送事件。我們可以通過create()方法來建立一個Observable。它決定什麼時候觸發事件以及怎麼傳送事件。在create()裡傳入了一個OnSubscribe,它會有一個call方法,它提供了一個Subscriber來通過onNext傳送事件。傳送完畢之後Subscriber會提供一個onComplete方法,來結束事件的傳送。

    Observable<String> mObservable = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            LogUtils.e("開始傳送事件");
            subscriber.onNext("Hello World");//通過onNext 傳送事件
            subscriber.onCompleted();//結束髮送事件
        }
    });
    
  2. 然後我還需要一個Subscribe用來接收接收Observable傳送的事件。

    Subscriber<String> mSubscriber = new Subscriber<String>() {
        //在監聽事件傳送剛開始也就是subscribe()剛開始,而事件還未傳送之前被呼叫,可以用於做初始化工作
        @Override
        public void onStart() {
            super.onStart();
            LogUtils.e("開始接收資料");
        }
    
        @Override
        public void onCompleted() {
            LogUtils.e("接收事件結束");
        }
        @Override
        public void onError(Throwable throwable) {
            LogUtils.e("接收事件發生錯誤:" + throwable.getMessage());
        }
        //對應Observable中的onNext對應,Observable中的onNext呼叫一次,這裡對應也會呼叫一次
        @Override
        public void onNext(String s) {
            Toast.makeText(MainActivity.this, "" + s, Toast.LENGTH_SHORT).show();
            LogUtils.e(s);
        }
    };
    

3.前面說,如果Observable沒有對應的Subscriber,不會發送任何事件。所以我們還需要SubscriberObservable的訂閱。

mObservable.subscribe(mSubscriber);

這樣就完成了事件的傳送於接收。

建立Observable的方式

在RxJava中建立Observable還有其它的方式

  1. 如果傳遞的資料是多個同類型的資料,可以使用以下的方式:

    //已傳送 “Hello”,”World”,”RxJava”,相當於呼叫三次onNext,並呼叫onComplete
    Observable observable = Observable.just(“Hello”, “World”,”RxJava”);

  2. 如果傳遞的資料是陣列:

    String[] strArr = {"Hello", "World","RxJava"};
    Observable observable = Observable.from(strArr);
    
  3. 如果傳遞的資料是集合:

    List<String> strList = new ArrayList<>();
    strList.add("Hello");
    strList.add("World");
    strList.add("RxJava");
    Observable observable = Observable.from(strList);
    

常用的操作符

map

map()在RxJava裡非常常用,它可以對事件進行變換。非常喜歡這個操作符,它可以將事件序列中的物件或整個傳送的整個序列進行變換,進行不同的處理。例如:我們想需要傳遞一個圖片的Bitmap集合,但是我們只有一個圖片的URL集合。我們就可以使用map對URL集合進行處理。

    List<String> strList = new ArrayList<>();
    strList.add("http://h.hiphotos.baidu.com/zhidao/pic/item/3812b31bb051f81991b9d8dbdcb44aed2f73e787.jpg");
    strList.add("http://cdn.duitang.com/uploads/item/201412/19/20141219154459_3P4G2.jpeg");
    strList.add("http://ww1.sinaimg.cn/crop.7.22.1192.1192.1024/5c6defebjw8epti0r9noaj20xc0y1n0x.jpg");
    Observable observable = Observable.from(strList)
            //map的引數是一個Func1類,它的第一個泛型是指傳遞資料型別,第二個引數是經過轉換過返回的資料型別
            //這裡我們轉換之前的資料型別是String,處理後返回的是Bitmap
            .map(new Func1<String, Bitmap>() {
                @Override
                public Bitmap call(String s) {
                     Bitmap bitmap = parseString2Bitmap(s);
                    return bitmap;
                }
            });
flatMap

flatMap的功能比較難解釋,我們先舉個例子啊;假如我們有若干個使用者買了我們若干的產品,我們想知道哪些產品比較受歡迎,需要我們列印一下這些使用者購買的產品。我們這裡只打印產品的名稱。

我們先準備一下資料:

    List<User> users = new ArrayList<>();
    for (int i = 0; i < 10; i++) {
        User user = new User();
        user.id = i;
        user.name = "UserName = " + i;
        user.address = "火星" + i + "號";
        for (int j = 0; j < 5; j++) {
            Product product = new Product();
            product.name = "ProductName" + j;
            product.price = j * j + "";
            product.number = j * 1000 + "";
            user.mProducts.add(product);
        }
        users.add(user);
    }

接下來我們來過濾這些使用者:

    Observable observable = Observable.from(users)
            //利用flatMap,將之前我們User集合的每個user中的Product集合提取出來構建一個新的Observable,然後再將product一次往下傳遞
            .flatMap(new Func1<User, Observable<Product>>() {
                @Override
                public Observable<Product> call(User user) {
                    //我們在建立第一個Observable時使用User集合,我們把每個User提取出來,獲取其中的Product集合,並利用Product集合建立一個新的Observable
                    return Observable.from(user.mProducts);
                }
                //通過上面的flatMap,使用Product集合建立新的Observable,我們在通過map將product的名稱提取出來,並且傳遞到Subscribe
            }).map(new Func1<Product, String>() {
                @Override
                public String call(Product p) {
                    return p.name;
                }
            })

這裡我們通過flatMapmap的結合,避免了使用for迴圈,而是直接將每個使用者名稱下的所有產品挨個傳遞出去,到Subscribe裡處理。

執行緒的切換

subscribeOnobserveOn

RxJava還有個比較牛B的地方,就是可以對執行緒進行自由的變換。比如主/子執行緒的切換。

RxJava 提供了subscribeOnobserveOn來實現執行緒的切換。可以上事件的產生和處理分佈在不同的執行緒。例如我們可以在子執行緒獲取網路資料,在主執行緒顯示這些資料。

預設情況下如果不指定執行緒,RxJava的所有操作都是在主執行緒裡的,在Android開發中如果設計到網路等操作,是會報異常的,我們可以使用subscribeOnobserveOn來實現執行緒的切換,來處理類似的這些情況。

比如我們現在有一個是從伺服器拉取資料的方法叫做getNetData(),它的返回值是String型別,我們都知道在Android中網路資料的訪問是不能在主執行緒裡進行的,我們只能在子執行緒裡進行,然後通過Handler傳送到主執行緒。這樣做起來稍微麻煩一些,如果我們使用RxJava就會很簡單。

    Observable observable = Observable.create(new Observable.OnSubscribe<String>() {
        @Override
        public void call(Subscriber<? super String> subscriber) {
            //獲取網路資料
            String result = getNetData();
            subscriber.onNext(result);
            subscriber.onCompleted();
        }
       //使用subscribeOn(),指定傳送事件所在的執行緒
    }).subscribeOn(Schedulers.newThread())
       //使用observeOn(),指定觀察者接收事件所在的執行緒
     .observeOn(AndroidSchedulers.mainThread());

然後我們根據上面,建立Subscriber,然後監聽著Observable傳送過來的資料就可以了。