Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android RxJava使用介紹(二) RxJava的操作符上

Android RxJava使用介紹(二) RxJava的操作符上

編輯:關於Android編程

上一篇文章我們通過一個簡單的例子來給大家展示了RxJava的基本用法,相信大家已經對RxJava有了大概的了解,由於上篇文章對RxJava的使用介紹都是點到為止,並沒有進行深入展開,也許你對RxJava有種名不副實的感覺。OK,下面我們就進入正題,一步步的揭開RxJava的神秘面紗!

一個例子

RxJava的強大之處,在於它提供了非常豐富且功能強悍的操作符,通過使用和組合這些操作符,你幾乎能完成所有你想要完成的任務,舉個例子如下:

現在有一個需求:app啟動時顯示一張圖片(一般是app的logo),也就是我們所說的歡迎頁,2-3秒後自動跳轉到主頁面。這不就是幾乎每個app都有的啟動頁需求嗎?幾乎不用思考,代碼如下:
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                finish();
            }
        },2000);
    }

使用RxJava的代碼實現如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        Observable.timer(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread()).map(l->{
            startActivity(new Intent(this, MainActivity.class));
            finish();
            return null;
        }).subscribe();
    }

這裡的RxJava使用了兩個操作符:一個是timer操作符,它的意思是延遲執行某個操作;一個是map操作符,它的意思是轉換某個執行結果。
恩,好像除了寫法不一樣,也沒看出RxJava有什麼優勢呢。好吧,繼續往下看!
2. 由於最近產品要做活動,為了在顯著的位置把活動的內容顯示給用戶,經過討論,就是在歡迎頁停留2秒後,要跳轉到活動內容的頁面(也就是一張廣告的圖片)上,然後在活動內容的頁面停留2-3秒,再跳轉到主頁面;

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        //開新線程從網絡獲取圖片
        AsyncAdImageFromNet();

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //mAdBitmapDrawable是從網絡獲取到的圖片,如果獲取到圖片,則顯示出來,否則直接跳轉到主頁面
                if(mAdBitmapDrawable != null){
                    view.setImageDrawable(mAdBitmapDrawable);
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                            finish();
                        }
                    }, 2000);
                } else {
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                }
            }
        }, 2000);

    }

這段代碼沒有考慮離線情況,即沒有網絡的情況下是顯示不出活動內容圖片的,最好是在有網絡的情況下就把圖片下載到本地緩存起來,不管有沒有網絡都裝載本地的緩存即可,改進後的代碼如下:

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.drawable.welcome);
        //本地圖片緩存路徑
        File localBitmapFile = new File(getLocalBitmapPath());
        if(localBitmapFile.exists())
            mAdBitmapDrawable = BitmapFactory.decodeFile(localBitmapFile);
        //開新線程從網絡獲取圖片
        AsyncAdImageFromNet();

        Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                //mAdBitmapDrawable是本地緩存獲取到的圖片,如果獲取到圖片,則顯示出來,否則直接跳轉到主頁面
                if(mAdBitmapDrawable != null){
                    view.setImageDrawable(mAdBitmapDrawable);
                    handler.postDelayed(new Runnable() {
                        @Override
                        public void run() {
                            startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                            finish();
                        }
                    }, 2000);
                } else {
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                }
            }
        }, 2000);

    }

仔細一看,代碼還是有問題,加載本地緩存圖片,如果圖片比較大,就會阻塞主線程,最好是把加載本地緩存圖片放在一個線程中執行,代碼真是越寫越亂,我們看看使用RxJava是怎麼做的呢?

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_welcome);

        ImageView view = (ImageView) findViewById(R.id.iv_welcome);
        view.setImageResource(R.mipmap.welcome);

        Observable.mergeDelayError(
                //在新線程中加載本地緩存圖片
                loadBitmapFromLocal().subscribeOn(Schedulers.io()),
                //在新線程中加載網絡圖片
                loadBitmapFromNet().subscribeOn(Schedulers.newThread()),
                Observable.timer(3,TimeUnit.SECONDS).map(c->null))
                //每隔2秒獲取加載數據
                .sample(2, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
                .flatMap(r->{
                    if(r==null)  //如果沒有獲取到圖片,直接跳轉到主頁面
                        return Observable.empty();
                    else { //如果獲取到圖片,則停留2秒再跳轉到主頁面
                        view.setImageDrawable(r);
                        return Observable.timer(2, TimeUnit.SECONDS);
                    }
                }).subscribe(
                r->{
                },
                e->{
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                },
                ()->{
                    startActivity(new Intent(WelcomeActivity.this, MainActivity.class));
                    finish();
                }
        );
    }

這裡使用了幾個操作符:首先是mergeDelayError,它的意思是合並幾個不同的Observable;sample的意思是每隔一段時間就進行采樣,在時間間隔范圍內獲取最後一個發布的Observable; flatMap的意思是把某一個Observable轉換成另一個Observable。

可以看到,使用了RxJava,整個代碼思路很清晰,不用考慮底層的線程同步、異步通知等內容,把主要精力都集中在如何實現業務上,這就是響應式函數編程的魅力!

操作符分類

通過上面的例子,大家應該看到了RxJava操作符的威力,下面我按類別把常用操作符分別介紹,其實很多內容都是來自於ReactiveX的官方網站,英文比較好的朋友可以參考(http://reactivex.io/)。
按照官方的分類,操作符大致分為以下幾種:

Creating Observables(Observable的創建操作符),比如:Observable.create()、Observable.just()、Observable.from()等等; Transforming Observables(Observable的轉換操作符),比如:observable.map()、observable.flatMap()、observable.buffer()等等; Filtering Observables(Observable的過濾操作符),比如:observable.filter()、observable.sample()、observable.take()等等; Combining Observables(Observable的組合操作符),比如:observable.join()、observable.merge()、observable.combineLatest()等等; Error Handling Operators(Observable的錯誤處理操作符),比如:observable.onErrorResumeNext()、observable.retry()等等; Observable Utility Operators(Observable的功能性操作符),比如:observable.subscribeOn()、observable.observeOn()、observable.delay()等等; Conditional and Boolean Operators(Observable的條件操作符),比如:observable.amb()、observable.contains()、observable.skipUntil()等等; Mathematical and Aggregate Operators(Observable數學運算及聚合操作符),比如:observable.count()、observable.reduce()、observable.concat()等等; 其他如observable.toList()、observable.connect()、observable.publish()等等;

創建型操作符

create操作符

create操作符是所有創建型操作符的“根”,也就是說其他創建型操作符最後都是通過create操作符來創建Observable的,其流程圖例如下:
這裡寫圖片描述

調用例子如下:<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;"> Observable.create(new Observable.OnSubscribe() { @Override public void call(Subscriber observer) { try { if (!observer.isUnsubscribed()) { for (int i = 1; i < 5; i++) { observer.onNext(i); } observer.onCompleted(); } } catch (Exception e) { observer.onError(e); } } } ).subscribe(new Subscriber() { @Override public void onNext(Integer item) { System.out.println("Next: " + item); } @Override public void onError(Throwable error) { System.err.println("Error: " + error.getMessage()); } @Override public void onCompleted() { System.out.println("Sequence complete."); } });

運行結果如下:
Next: 1
Next: 2
Next: 3
Next: 4
Sequence complete.

在使用create操作符時,最好要在回調的call函數中增加isUnsubscribed的判斷,以便在subscriber在取消訂閱時不會再執行call函數中相關代碼邏輯,從而避免導致一些意想不到的錯誤出現;

from操作符

from操作符是把其他類型的對象和數據類型轉化成Observable,其流程圖例如下:
這裡寫圖片描述
調用例子如下:

Integer[] items = { 0, 1, 2, 3, 4, 5 };
Observable myObservable = Observable.from(items);

myObservable.subscribe(
    new Action1() {
        @Override
        public void call(Integer item) {
            System.out.println(item);
        }
    },
    new Action1() {
        @Override
        public void call(Throwable error) {
            System.out.println("Error encountered: " + error.getMessage());
        }
    },
    new Action0() {
        @Override
        public void call() {
            System.out.println("Sequence complete");
        }
    }
);

運行結果如下:
0
1
2
3
4
5
Sequence complete

just操作符

just操作符也是把其他類型的對象和數據類型轉化成Observable,它和from操作符很像,只是方法的參數有所差別,其流程圖例如下:
這裡寫圖片描述
調用例子如下:

Observable.just(1, 2, 3)
          .subscribe(new Subscriber() {
        @Override
        public void onNext(Integer item) {
            System.out.println("Next: " + item);
        }

        @Override
        public void onError(Throwable error) {
            System.err.println("Error: " + error.getMessage());
        }

        @Override
        public void onCompleted() {
            System.out.println("Sequence complete.");
        }
    });

運行結果如下:
Next: 1
Next: 2
Next: 3
Sequence complete.

defer操作符

defer操作符是直到有訂閱者訂閱時,才通過Observable的工廠方法創建Observable並執行,defer操作符能夠保證Observable的狀態是最新的,其流程實例如下:
這裡寫圖片描述

下面通過比較defer操作符和just操作符的運行結果作比較:

        i=10;
        Observable justObservable = Observable.just(i);
        i=12;
        Observable deferObservable = Observable.defer(new Func0>() {
            @Override
            public Observable

其中i是類的成員變量,運行結果如下:
just result:10
defer result:15

可以看到,just操作符是在創建Observable就進行了賦值操作,而defer是在訂閱者訂閱時才創建Observable,此時才進行真正的賦值操作

timer操作符

timer操作符是創建一串連續的數字,產生這些數字的時間間隔是一定的;這裡有兩種情況:

一種是隔一段時間產生一個數字,然後就結束,可以理解為延遲產生數字,其流程實例如下:
這裡寫圖片描述 一種是每隔一段時間就產生一個數字,沒有結束符,也就是是可以產生無限個連續的數字,其流程實例如下:
這裡寫圖片描述

timer操作符默認情況下是運行在一個新線程上的,當然你可以通過傳入參數來修改其運行的線程。
下面是調用例子:


        //每隔兩秒產生一個數字
        Observable.timer(2, 2, TimeUnit.SECONDS).subscribe(new Subscriber() {
            @Override
            public void onCompleted() {
                System.out.println("Sequence complete.");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("error:" + e.getMessage());
            }

            @Override
            public void onNext(Long aLong) {
                System.out.println("Next:" + aLong.toString());
            }
        });

運行結果如下:
Next:0
Next:1
Next:2
Next:3
……

interval操作符

interval操作符是每隔一段時間就產生一個數字,這些數字從0開始,一次遞增1直至無窮大;interval操作符的實現效果跟上面的timer操作符的第二種情形一樣。以下是流程實例:
這裡寫圖片描述

interval操作符默認情況下是運行在一個新線程上的,當然你可以通過傳入參數來修改其運行的線程。

調用例子就不列出了,基本跟上面timer的調用例子一樣。

range操作符

range操作符是創建一組在從n開始,個數為m的連續數字,比如range(3,10),就是創建3、4、5…12的一組數字,其流程實例如下:
這裡寫圖片描述

調用例子如下:

//產生從3開始,個數為10個的連續數字
        Observable.range(3,10).subscribe(new Subscriber() {
            @Override
            public void onCompleted() {
                System.out.println("Sequence complete.");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("error:" + e.getMessage());
            }

            @Override
            public void onNext(Integer i) {
                System.out.println("Next:" + i.toString());
            }
        });

運行結果如下:
Next:3
Next:4
Next:5
Next:6
….
Next:12
Sequence complete.

repeat/repeatWhen操作符

repeat操作符是對某一個Observable,重復產生多次結果,其流程實例如下:
這裡寫圖片描述

repeatWhen操作符是對某一個Observable,有條件地重新訂閱從而產生多次結果,其流程實例如下:
這裡寫圖片描述
repeat和repeatWhen操作符默認情況下是運行在一個新線程上的,當然你可以通過傳入參數來修改其運行的線程。

repeat調用例子如下:

//連續產生兩組(3,4,5)的數字
        Observable.range(3,3).repeat(2).subscribe(new Subscriber() {
            @Override
            public void onCompleted() {
                System.out.println("Sequence complete.");
            }

            @Override
            public void onError(Throwable e) {
                System.out.println("error:" + e.getMessage());
            }

            @Override
            public void onNext(Integer i) {
                System.out.println("Next:" + i.toString());
            }
        });

運行結果如下:
Next:3
Next:4
Next:5
Next:3
Next:4
Next:5
Sequence complete.

好了,本篇文章到此為止,後面會繼續介紹RxJava的其他操作符,敬請期待!

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved