前言
終于到了講RxJava這一期,RxJava是筆者個人非常喜歡的一個開源庫,它很好的將鏈式編程風格和異步結合在一起。RxJava其實已經推出很久了,可以說是已經很火了,但是目前仍然還有相當一部分Android開發者沒有使用過,甚至說是想用,卻不知道怎么用,或者不知道自己的項目哪里可以用到,本著讓廣大開發者理解并且上手項目,從放棄到入門,故推出這邊文章。
注:本文所有的具體代碼實現都在文章最后的github鏈接上
學習RxJava2.0之前需不需要學習RxJava1.0
首先,RxJava1.0和RxJava2.0的核心思想都是觀察者模式,只不過RxJava2.0在RxJava1.0的基礎對一些方法進行了優化,方便于開發者更好地理解其編程思想,同時又增加了一部分新的方法解決1.0存在的問題,例如背壓等。所以,如果你學習過RxJava1.0那么很好,你可能已經理解了什么是觀察者模式;如果你沒有學過RxJava1.0,當然也不必著急,因為本文將從最基本的觀察者模式講起,讓你從最基本最簡單的角度入手RxJava。綜上所述,不管你是不是學過RxJava1.0,都不會影響你學習本篇文章。
觀察者模式
在學習RxJava2.0之前,我們必須要弄明白什么是觀察者模式。按照我的慣例,先上一個百度百科的權威介紹
簡單介紹一下,A和B兩個,A是被觀察者,B是觀察者,B對A進行觀察,B并不是需要時刻盯著A,而是A如果發生了變化,會主動通知B,B會對應做一些變化。舉個例子,假設A是連載小說,B是讀者,讀者訂閱了連載小說,當小說出現了新的連載的時候,會推送給讀者。讀者不用時刻盯著小說連載,而小說有了新的連載會主動推送給讀者。這就是觀察者模式。而RxJava正是基于觀察者模式開發的。
RxJava2.0的基本使用
理解好了觀察者模式,我們開始RxJava2.0的學習。首先引入RxJava2.0相關的類庫。
compile 'io.reactivex.rxjava2:rxjava:2.0.1'
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
正確使用姿勢:
第一步:創建連載小說(被觀察者)
//被觀察者
Observable novel=Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("連載1");
emitter.onNext("連載2");
emitter.onNext("連載3");
emitter.onComplete();
}
});
Observable中文意思就是被觀察者,通過create方法生成對象,里面放的參數ObservableOnSubscribe<T>,可以理解為一個計劃表,泛型T是要操作對象的類型,重寫subscribe方法,里面寫具體的計劃,本文的例子就是推送連載1、連載2和連載3,在subscribe中的ObservableEmitter<String>對象的Emitter是發射器的意思。ObservableEmitter有三種發射的方法,分別是void onNext(T value)、void onError(Throwable error)、void onComplete(),onNext方法可以無限調用,Observer(觀察者)所有的都能接收到,onError和onComplete是互斥的,Observer(觀察者)只能接收到一個,OnComplete可以重復調用,但是Observer(觀察者)只會接收一次,而onError不可以重復調用,第二次調用就會報異常。
第二步:創建讀者(觀察者)
//觀察者
Observer<String> reader=new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
mDisposable=d;
Log.e(TAG,"onSubscribe");
}
@Override
public void onNext(String value) {
if ("2".equals(value)){
mDisposable.dispose();
return;
}
Log.e(TAG,"onNext:"+value);
}
@Override
public void onError(Throwable e) {
Log.e(TAG,"onError="+e.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG,"onComplete()");
}
};
通過new創建接口,并實現其內部的方法,看方法其實就應該差不多知道干嘛的,onNext、onError、onComplete都是跟被觀察者發射的方法一一對應的,這里就相當于接收了。onSubscribe(Disposable d)里面的Disposable對象要說一下,Disposable英文意思是可隨意使用的,這里就相當于讀者和連載小說的訂閱關系,如果讀者不想再訂閱該小說了,可以調用 mDisposable.dispose()取消訂閱,此時連載小說更新的時候就不會再推送給讀者了。
第三步:讀者和連載小說建立訂閱關系
novel.subscribe(reader);//一行代碼搞定
在這里細心的你,可能已經發現了怎么是小說訂閱了讀者,之所以這樣,是因為RxJava主要是想保持自己的鏈式編程,不得不把Observable(被觀察者)放在前面,這里大家可以理解為小說被讀者訂閱了。
這里我們先看一下輸出效果
小結一下:這就是RxJava2.0最最簡單的用法,創建小說,創建讀者,建立訂閱關系,記住這三步,你就能實現一個最簡單的RxJava2.0的用法。
RxJava2.0的異步和鏈式編程
前言里面有提到,RxJava是支持異步的,但是RxJava是如何做到的呢?這里就需要Scheduler。Scheduler,英文名調度器,它是RxJava用來控制線程。當我們沒有設置的時候,RxJava遵循哪個線程產生就在哪個線程消費的原則,也就是說線程不會產生變化,始終在同一個。然后我們一般使用RxJava都是后臺執行,前臺調用,本著這個原則,我們需要調用observeOn(AndroidSchedulers.mainThread()),observeOn是事件回調的線程,AndroidSchedulers.mainThread()一看就知道是主線程,subscribeOn(Schedulers.io()),subscribeOn是事件執行的線程,Schedulers.io()是子線程,這里也可以用Schedulers.newThread(),只不過io線程可以重用空閑的線程,因此多數情況下 io() 比 newThread() 更有效率。前面的代碼根據異步和鏈式編程的原則,我們可以寫成
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> emitter) throws Exception {
emitter.onNext("連載1");
emitter.onNext("連載2");
emitter.onNext("連載3");
emitter.onComplete();
}
})
.observeOn(AndroidSchedulers.mainThread())//回調在主線程
.subscribeOn(Schedulers.io())//執行在io線程
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
Log.e(TAG,"onSubscribe");
}
@Override
public void onNext(String value) {
Log.e(TAG,"onNext:"+value);
}
@Override
public void onError(Throwable e) {
Log.e(TAG,"onError="+e.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG,"onComplete()");
}
});
這里就是RxJava最常用的寫法,異步+鏈式編程,還要再說一下,subscribe的方法重載,subscribe()方法里什么參數也不放是空實現,也就是說連載小說無論出什么連載,讀者都不關心,推送過來了也不讀,如果讀者只關心onNext方法里的內容,可以直接重載subscribe(Consumer<? spuer T> onNext)這個方法,會減少代碼,當然如果是初學者還是建議創建Observer對象。
應用場景
說了這么多RxJava2.0的用法,你一定要問了到底在什么情況下使用?下面先給大家介紹一下典型的場景。
一、與Retrofit聯用
Retrofit+RxJava的上網模式已經非?;鹆?,如果有不了解的可以看筆者的這篇文章http://www.lxweimin.com/writer#/notebooks/5118090/notes/25405151
二、Rxpermissions等類庫的使用
基于RxJava的開源類庫Rxpermissions、RxBinding以及RxBus在很多項目中已經非常常見,并且被證明了是極其好用的。
三、所有用到異步的地方
因為RxJava就是一個支持異步的鏈式編程,所以所有的用到異步的地方,我們都可以用RxJava來完成,下面給大家舉幾個例子。
定時執行任務
Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(ObservableEmitter<Integer> emitter) throws Exception {
emitter.onNext(123);
sleep(3000);
emitter.onNext(456);
}
}).observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.subscribe(new Consumer<Integer>() {
@Override
public void accept(Integer integer) throws Exception {
Log.e(TAG,integer+"");
}
}, new Consumer<Throwable>() {
@Override
public void accept(Throwable throwable) throws Exception {
}
}, new Action() {
@Override
public void run() throws Exception {
}
});
看完上面的代碼你肯定在想,這么多代碼,干嘛不直接new Handler().postDelayed()。如果你的程序線程里面做的操作很簡單,那么你用new Handler().postDelayed()無所謂,但是如果你的操作很復雜,那么這時候就體現出了RxJava的好處了,借用扔物線大神的一句話就是"隨著程序邏輯變得越來越復雜,RxJava依然能夠保持簡潔"。
下面來說一個復雜的操作,比如我們要依次加載10張圖片(加載圖片是耗時過程),其中第六張我們延時3秒加載,第7張我們復制到sd卡里,第8張我們要上網絡,那么請問你要怎么做,如果用Handler,必然是各種嵌套,各種邏輯復雜得讓你再看一眼都難受,但是如果使用RxJava呢?
Observable.create(new ObservableOnSubscribe<Drawable>() {
@Override
public void subscribe(ObservableEmitter<Drawable> emitter) throws Exception {
for (int i=0;i<drawableRes.length;i++){
Drawable drawable=getResources().getDrawable(drawableRes[i]);
//第6個圖片延時3秒后架子
if (i==5){
sleep(3000);
}
//復制第7張圖片到sd卡
if (i==6){
Bitmap bitmap=((BitmapDrawable)drawable).getBitmap();
saveBitmap(bitmap,"test.png", Bitmap.CompressFormat.PNG);
}
//上傳到網絡
if (i==7){
updateIcon(drawable);
}
emitter.onNext(drawable);
}
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Drawable>() {
@Override
public void accept(Drawable drawable) throws Exception {
//回調后在UI界面上展示出來
}
});
沒有任何嵌套,邏輯依然簡潔,這就是RxJava的好處。
總結
RxJava2.0是非常好用的一個異步鏈式庫,遵循觀察者模式。理解觀察者模式可以根據連載小說和讀者的關系,被觀察者是連載小說,觀察者是讀者,讀者訂閱小說,當小說有了新的連載推送給讀者,這就是觀察者模式;創建RxJava最簡單的步驟,一、創建被觀察者對象,二、創建觀者對象,三創建訂閱關系;RxJava2.0的應用場景,只要記得一句話就是所有的異步都可以用RxJava來做就可以了,尤其是復雜的場景,越是復雜的場景越能體現RxJava的好處。關于RxJava的文章,筆者將會繼續推出兩篇,一篇是《RxJava從入門到進階》講的是RxJava的一些進階操作,例如變換、常用操作符和背壓;另一篇是RxJava相關的類庫的介紹和使用,例如文章中提到的RxBinding、RxPerssions等等。如果喜歡筆者,可以關注一波,謝謝!
最后放上我的github地址(本次demo的代碼基本都在文章上了,不下也可以):https://github.com/kaka10xiaobang/RxJavaDemo