Android RxJava使用介紹(二) RxJava的操作符
上一篇文章我們通過一個簡單的例子來給大家展示了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的,其流程圖例如下:
呼叫例子如下:
Observable.create(new Observable.OnSubscribe<Integer>() {
@Override
public void call(Subscriber<? super Integer> 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<Integer>() {
@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<Integer>() {
@Override
public void call(Integer item) {
System.out.println(item);
}
},
new Action1<Throwable>() {
@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<Integer>() {
@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<Observable<Object>>() {
@Override
public Observable<Object> call() {
return Observable.just(i);
}
});
i=15;
justObservable.subscribe(new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Object o) {
System.out.println("just result:" + o.toString());
}
});
deferObservable.subscribe(new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(Object o) {
System.out.println("defer result:" + o.toString());
}
});
}
其中i是類的成員變數,執行結果如下:
just result:10
defer result:15
可以看到,just操作符是在建立Observable就進行了賦值操作,而defer是在訂閱者訂閱時才建立Observable,此時才進行真正的賦值操作
timer操作符
timer操作符是建立一串連續的數字,產生這些數字的時間間隔是一定的;這裡有兩種情況:
- 一種是隔一段時間產生一個數字,然後就結束,可以理解為延遲產生數字,其流程例項如下:
- 一種是每隔一段時間就產生一個數字,沒有結束符,也就是是可以產生無限個連續的數字,其流程例項如下:
timer操作符預設情況下是執行在一個新執行緒上的,當然你可以通過傳入引數來修改其執行的執行緒。
下面是呼叫例子:
//每隔兩秒產生一個數字
Observable.timer(2, 2, TimeUnit.SECONDS).subscribe(new Subscriber<Long>() {
@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<Integer>() {
@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<Integer>() {
@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.
repeatWhen呼叫例子如下:
Observable.just(1,2,3).repeatWhen(new Func1<Observable<? extends Void>, Observable<?>>() {
@Override
public Observable<?> call(Observable<? extends Void> observable) {
//重複3次
return observable.zipWith(Observable.range(1, 3), new Func2<Void, Integer, Integer>() {
@Override
public Integer call(Void aVoid, Integer integer) {
return integer;
}
}).flatMap(new Func1<Integer, Observable<?>>() {
@Override
public Observable<?> call(Integer integer) {
System.out.println("delay repeat the " + integer + " count");
//1秒鐘重複一次
return Observable.timer(1, TimeUnit.SECONDS);
}
});
}
}).subscribe(new Subscriber<Integer>() {
@Override
public void onCompleted() {
System.out.println("Sequence complete.");
}
@Override
public void onError(Throwable e) {
System.err.println("Error: " + e.getMessage());
}
@Override
public void onNext(Integer value) {
System.out.println("Next:" + value);
}
});
執行結果如下:
Next:1
Next:2
Next:3
repeat the 1 count
Next:1
Next:2
Next:3
repeat the 2 count
Next:1
Next:2
Next:3
repeat the 3 count
Next:1
Next:2
Next:3
Sequence complete.
好了,本篇文章到此為止,後面會繼續介紹RxJava的其他操作符,敬請期待!
相關文章
- Android RxJava使用介紹(三) RxJava的操作符AndroidRxJava
- Android RxJava使用介紹(四) RxJava的操作符AndroidRxJava
- Android RxJava:基礎介紹與使用AndroidRxJava
- Android RxJava使用介紹(一) Hello WorldAndroidRxJava
- RxJava 操作符系列二RxJava
- RxJava操作符系列二RxJava
- RxJava 和 RxAndroid 二(操作符的使用)RxJavaAndroid
- Rxjava2操作符(二)RxJava
- 深入淺出RxJava(二:操作符)RxJava
- 一篇不太一樣的RxJava介紹(二):關於操作符背後的故事RxJava
- RxJava常用操作符RxJava
- RxJava操作符列表RxJava
- Kotlin 使用Rxjava的compose()操作符KotlinRxJava
- 3章 RxJava操作符RxJava
- RxJava操作符系列一RxJava
- RxJava操作符系列三RxJava
- RxJava 操作符系列五RxJava
- RxJava操作符系列四RxJava
- RxJava 知識梳理(2) RxJava2 操作符實戰RxJava
- RxJava操作符之建立操作符(三)RxJava
- part05_Rxjava操作符RxJava
- Rxjava2操作符(三)RxJava
- 詳解Android RxJava的使用AndroidRxJava
- Rxjava2的簡單使用與基本操作符RxJava
- RxJava2原始碼分析(二):操作符原理分析RxJava原始碼
- 一篇不太一樣的RxJava介紹RxJava
- RxJava操作符之組合操作符(六)RxJava
- RxJava操作符之轉換操作符(四)RxJava
- RxJava操作符之過濾操作符(五)RxJava
- 解剖 RxJava 之變換操作符RxJava
- RxJava2 操作符總結RxJava
- RxJava2.0——變換操作符RxJava
- 解剖 RxJava 之過濾操作符RxJava
- RxJava操作符之Transforming ObservablesRxJavaORM
- 深入淺出RxJava(2):操作符RxJava
- Android 淺析 RxJava (一) 使用AndroidRxJava
- Android Retrofit 2.0(二)使用教程OkHttp3 + Gson + RxJavaAndroidHTTPRxJava
- Rxjava2操作符入門(一)RxJava