Rxjava2的簡單使用與基本操作符
一 、關於Rxjava
非同步:RxJava 在 GitHub 主頁上的自我介紹是 "a library for composing asynchronous and event-based programs using observable sequences for the Java VM"(一個在 Java VM 上使用可觀測的序列來組成非同步的、基於事件的程式的庫)。
簡潔:非同步操作很關鍵的一點是程式的簡潔性,因為在排程過程比較複雜的情況下,非同步程式碼經常會既難寫也難被讀懂。RxJava 的優勢也是簡潔,但它的簡潔的與眾不同之處在於,隨著程式邏輯變得越來越複雜,它依然能夠保持簡潔。
二 、基本概念
- Observable:發射源,在觀察者模式中稱為被觀察者
- Observer:接收源,在觀察者模式中成為觀察者,可接收Observable、Subject發射的資料;
- Subscriber:“訂閱者”,也是接收源,接收源在觀察者模式中成為觀察者。Subscriber實現了Observer介面,比Observer多了一個最重要的方法unsubscribe( ),用來取消訂閱。
- subscribe:訂閱,Observable和Observer通過subscribe()進行訂閱
- Subscription:Observable呼叫subscribe( )方法返回的物件,同樣有unsubscribe( )方法,可以用來取消訂閱事件;
-
Disposable
:用於維繫觀察者、被觀察者之間的聯絡。 - Event:事件。
1、基本呼叫
新增依賴
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.3'
建立被觀察者
Observable<String> normalObservable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
observableEmitter.onNext("msg1");//通過onNext(),發射一個"msg1"的String
observableEmitter.onNext("msg2");//通過onNext(),發射一個"msg2"的String
observableEmitter.onComplete();//發射完成,這種方法需要手動呼叫onCompleted,才會回撥Observer的onCompleted方法
}
});
建立觀察者
Observer<String> mObserver = new Observer<String>() {
@Override
public void onSubscribe(Disposable disposable) {
//d.dispose();移除訂閱關係
//d.isDisposed()是否發生訂閱關係
}
@Override
public void onNext(String s) {
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
}
呼叫subscribe實現訂閱
normalObservable.subscribe(mObserver);
2、鏈式呼叫
當然我們也可以使用鏈式操作的寫法
其中Consumer引數的方法表示下游只對我們關心onNext事件,或Throwable事件進行處理
Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
}
}).subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
}
});
三、執行緒切換
我們在請求網路時必須是將其放在子執行緒執行,然後在安卓主執行緒中更新Ui
程式碼 | 含義 |
---|---|
Schedulers.immediate |
直接在當前執行緒執行。 |
Schedulers.newThread |
啟用新執行緒,並線上程執行操作。 |
Schedulers.io |
內部是一個無數量上限的的執行緒池,可以重用空閒的執行緒,不要把計算工作放在io 中。 |
Schedulers.computation |
使用固定的執行緒池,大小為CPU 核數。 |
-
subscribeOn()
:指定Observable執行緒如
subscribeOn(Schedulers.io())
在IO執行緒中請求網路 -
observeOn()
:指定Observer執行緒如
observeOn(AndroidSchedulers.mainThread())
在主執行緒中更新介面
Observable.create(new ObservableOnSubscribe<Resp>() {
@Override
public void subscribe(ObservableEmitter<Resp> e) throws Exception {
//模擬登陸
Call<Resp> respCall = api.login(new User(username, password));
Resp resp = respCall.execute().body();
e.onNext(resp);
}
})
//設定請求網路在io執行緒內執行、子執行緒中執行
.subscribeOn(Schedulers.io())
//設定更新ui在安卓主執行緒中執行
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<String>() {
@Override
public void accept(String s) throws Exception {
//更新UI
}
});
四、操作符
操作符變換符是RxJava中一個很重要的概念,也是其簡潔很重要的原因,這裡整理一些很常見的操作符。
》》1.使用just( ),建立一個Observable並自動為你呼叫onNext( )發射資料(最多可傳送9個)
Observable justObservable = Observable.just("just1","just2");//依次傳送"just1"和"just2"
String []justs={"just1","just2"};
Observable.fromArray(justs)//傳入陣列,類似於just();
》》2.使用from( ),遍歷集合,傳送每個item
List<String> list = new ArrayList<>();
list.add("from1");
list.add("from2");
list.add("from3");
Observable fromObservable = Observable.from(list); //遍歷list 每次傳送一個
注意:just()方法也可以傳list,但是傳送的是整個list物件,而from()傳送的是list的一個item
》》3.使用defer( ),有觀察者訂閱時才建立Observable,並且為每個觀察者建立一個新的Observable
Observable deferObservable = Observable.defer(new Func0<Observable<String>>() {
@Override
//注意此處的call方法沒有Subscriber引數
public Observable<String> call() {
return Observable.just("deferObservable");
}});
》》4.使用interval( )建立一個按固定時間間隔發射整數序列的Observable,可用作定時器
Observable intervalObservable = Observable.interval(1, TimeUnit.SECONDS);//每隔一秒傳送一次
》》5.使用range( ),建立一個發射特定整數序列的Observable,第一個引數為起始值,第二個為傳送的個數,如果為0則不傳送,負數則拋異常
Observable rangeObservable = Observable.range(10, 5);//將傳送整數10,11,12,13,14
》》6.使用timer( ),建立一個Observable,它在一個給定的延遲後發射一個特殊的值,等同於Android中Handler的postDelay( )方法
Observable timeObservable = Observable.timer(3, TimeUnit.SECONDS); //3秒後發射一個值
》》7.使用repeat( ),建立一個重複發射特定資料的Observable
Observable repeatObservable = Observable.just("repeatObservable").repeat(3);//重複發射3次
》》8.使用concat( ),連線兩個被訂閱者,訂閱者將會按照a->b
的順序收到兩個被訂閱者所發射的訊息。
final String[] aStrings = {"A1", "A2", "A3", "A4"};
final String[] bStrings = {"B1", "B2", "B3"};
final Observable<String> aObservable = Observable.fromArray(aStrings);
final Observable<String> bObservable = Observable.fromArray(bStrings);
Observable.concat(aObservable, bObservable);
輸出A1", "A2", "A3", "A4","B1", "B2", "B3"
》》9.使用window( ),每隔n秒,發射這段時間內的資料,不是有資料就發射
Observable windowObservable=Observable.interval(1, TimeUnit.SECONDS).window(3, TimeUnit.SECONDS);//3秒後,發射前三秒所發射的資料
五、變換操作符
》》1. Map:最常用且最實用的操作符之一,將物件轉換成另一個物件發射出去,應用範圍非常廣,如資料的轉換,資料的預處理等。(如我們傳入使用者id需要查詢使用者資訊,我們就可以使用map建立id返回user物件)
例一:資料型別轉換,改變最終的接收的資料型別。假設傳入本地圖片路徑,根據路徑獲取圖片的Bitmap。
Observable.just(filePath).map(new Func1<String, Bitmap>() {
@Override
public Bitmap call(String path) {
return getBitmapByPath(path);
}}).subscribe(new Action1<Bitmap>() {
@Override
public void call(Bitmap bitmap) {
//獲取到bitmap,顯示
}});
例二:對資料進行預處理,最後得到理想型資料。實際開發過程中,從後臺介面獲取到的資料也許不符合我們想要的,這時候可以在獲取過程中對得到的資料進行預處理(結合Retrofit)。
Observable.just("12345678").map(new Func1<String, String>() {
@Override
public String call(String s) {
return s.substring(0,4);//只要前四位
}})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i("mytag",s);
}});
》》2. FlatMap:和Map很像但又有所區別,Map只是轉換髮射的資料型別,而FlatMap可以將原始Observable轉換成另一個Observable。
例:
需要使用的school類,student類就不展示了,儲存一些學生基本資訊的欄位
public class School {
private String name;
private List<Student> studentList;
......
class studengt{
......
}
}
List<School> schoolList = new ArrayList<>();
首先假設要列印全國所有學校的名稱,可以直接用Map:
Observable.from(schoolList).map(new Func1<School, String>() {
@Override
public String call(School school) {
return school.getName();
}}).subscribe(new Action1<String>() {
@Override
public void call(String schoolName) {
Log.i(TAG,schoolName);
}});
再進一步,列印學校所有學生的姓名,先使用map
Observable.from(schoolList).map(new Func1<School, School.Student>() {
@Override
public School.Student call(School school) {
return school.getStudentList();//錯誤的地方
}}).subscribe(new Action1<School.Student>() {
@Override
public void call(School.Student student) {
Log.i(TAG,student.getName());
}});
看似可行,但事實上,這是一段錯誤的程式碼,細心的人就會發現錯誤的地方 school.getStudentList()返回的時list集合
Map是一對一的關係,無法將單一的School物件轉變成多個Student。FlatMap可以改變原始Observable變成另外一個Observable,如果我們能利用from()操作符把school.getStudentList()變成另外一個Observable,現在使用FlatMap實現
Observable.from(schoolList).flatMap(new Func1<School, Observable<School.Student>>() {
@Override
public Observable<School.Student> call(School school) {
return Observable.from(school.getStudentList()); //關鍵,將學生列表以另外一個Observable發射出去
}}).subscribe(new Action1<School.Student>() {
@Override
public void call(School.Student student) {
Log.i(TAG,student.getName());
}});
》》3. Buffer:快取,可以設定快取大小,快取滿後,以list的方式將資料傳送出去;例:
Observable.just(1,2,3).buffer(2).subscribe(new Action1<List<Integer>>() {
@Override
public void call(List<Integer> list) {
Log.i(TAG"size:"+list.size());
}});
執行列印結果如下:
MainActivity.this: size:2
MainActivity.this: size:1
Buffer和Map經常一起使用,通常發生在從後臺取完資料,對一個List中的資料進行預處理後,再用Buffer快取後一起傳送,保證最後資料接收還是一個List,如:
List<School> schoolList = new ArrayList<>();
Observable.from(schoolList).map(new Func1<School, School>() {
@Override
public School call(School school) {
school.setName("NB大學"); //將所有學校改名
return school;
}}).buffer(schoolList.size()) //快取起來,最後一起傳送
.subscribe(new Action1<List<School>>() {
@Override
public void call(List<School> schools) {
}});
六 、過濾操作符
》》1.Take:發射前n項資料,還是用上面的例子,假設不要改所有學校的名稱了,就改前四個學校的名稱:
Observable.from(schoolList).take(4).map(new Func1<School, School>() {
@Override
public School call(School school) {
school.setName("NB大學");
return school;
}}).buffer(4).subscribe(new Action1<List<School>>() {
@Override
public void call(List<School> schools) {
}});
》》2.Distinct:去掉重複的項,比較好理解
Observable.just(1, 2, 1, 1, 2, 3)
.distinct()
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer item) {
System.out.println("Next: " + item);
}
});
輸出
Next: 1
Next: 2
Next: 3
》》3.Filter:過濾,通過謂詞判斷的項才會被髮射,例如,發射小於4的資料
Observable.just(1, 2, 3, 4, 5)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer item) {
return( item < 4 );
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer item) {
System.out.println("Next: " + item);
}});
輸出:
Next: 1
Next: 2
Next: 3
》》window:
關於其他操作符或詳情檢視官網:RxJava使用以及操作符
六、注意事項
1、RxBinding的使用
RxBinding是在RxJava的基礎上封裝的一些操作,可以處理常用的一些UI的響應問題,這裡具體實現就不分析了,只整理一些常用的方法作為記錄。
新增依賴:
implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha1'
1.1、常用方法:
1.1.1、RxView
-
RxView.clicks().throttleFirst(long windowDuration, TimeUnit unit)
指定的時間windowDuration
內,點選clicks
事件只響應一次 -
RxView.longClicks()
長按監聽 -
RxView.draws()
繪製監聽 -
RxView.drags()
拖拽監聽 -
RxView.scrollChangeEvents()
滑動觸發 - .....
例:按鈕防抖,指定時間內事件只響應1次
//2秒內,按鈕點選事件只響應1次
RxView.clicks(btn)
.throttleFirst(2, TimeUnit.SECONDS)
.subscribe(new Consumer<Object>() {
@Override
public void accept(Object o) throws Exception {
}
}
1.1.2、RxTextView
-
RxTextView.textChanges()
EditText輸入監聽 -
RxTextView.textChangeEvents()
封裝了TextWatcher文字改變的監聽,返回資料的型別為TextViewTextChangeEvent,內部包含詳細的文字改變資料。 -
RxTextView.editorActions()
監聽了軟鍵盤的回車點選 -
RxTextView.editorActionEvents()
監聽了軟鍵盤的回車點選,返回型別為TextViewEditorActionEvent。 - ......
例:監聽文字變化
RxTextView.textChanges(et)
.subscribe(new Consumer<CharSequence>() {
@Override
public void accept(CharSequence charSequence) throws Exception {
}
);
1.1.3、RxCompoundButton
RxCompoundButton.checkedChanges()
選中狀態改變事件-
.....
RxView.clicks(btnLogin) .subscribe(o -> { RxCompoundButton.checked(cb).accept(true); })); RxCompoundButton.checkedChanges(cb) .subscribe(aBoolean -> { ...... });
2、避免記憶體洩漏
Activity被銷燬時,我們的後臺任務沒有執行完,那麼就會導致Activity不能正常回收,而對於每一個Observer,都會有一個Disposable物件用於管理。
在Observer
的onSubscribe
回撥中,會傳入一個Disposable
物件,下游可以通過該物件的dispose()
方法主動切斷和上游的聯絡,在這之後上游的observableEmitter.isDisposed()
方法將返回true
。當上遊和下游的聯絡切斷之後,下游收不到包括onComplete/onError
在內的任何事件,若此時上游再呼叫onError
方法傳送事件,那麼將會報錯。
為避免造成記憶體洩漏,我們需要將其將入到該集合當中,在Activity的onDestroy方法中,呼叫它的clear方法,就能避免記憶體洩漏的發生。
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private CompositeDisposable compositeDisposable;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
compositeDisposable=new CompositeDisposable();
Observable<String> observable = Observable.create(new ObservableOnSubscribe<String>() {
@Override
public void subscribe(ObservableEmitter<String> observableEmitter) throws Exception {
observableEmitter.onNext("msg");
}
});
DisposableObserver<String> disposableObserver = new DisposableObserver<String>() {
@Override
public void onNext(String s) {
Log.i(TAG, "onNext: "+s);
}
@Override
public void onError(Throwable throwable) {
}
@Override
public void onComplete() {
}
};
observable.subscribe(disposableObserver);
compositeDisposable.add(disposableObserver);
}
@Override
protected void onDestroy() {
compositeDisposable.clear();
super.onDestroy();
}
}
相關文章
- RxJava2與RxJava1的簡單對比RxJava
- Rxjava2操作符(二)RxJava
- Rxjava2操作符(三)RxJava
- RxJava2 操作符總結RxJava
- Rxjava2操作符入門(一)RxJava
- RxJava2操作符學習筆記RxJava筆記
- Dubbo學習筆記(一)基本概念與簡單使用筆記
- MySQL資料庫的基本使用簡單易懂MySql資料庫
- Rxjava2與Retrofit2的使用RxJava
- webstorm簡單介紹,webstrom基本使用WebORM
- jQuery-簡介與基本使用jQuery
- 簡單介紹標準庫fmt的基本使用
- mysql的簡單基本操作MySql
- RxJava2原始碼分析(二):操作符原理分析RxJava原始碼
- RxJava2進階教程(一)——建立型操作符RxJava
- RxJava2的使用RxJava
- RCNN的安裝與簡單使用CNN
- RediSearch的簡單使用與總結Redis
- 基於RxJava2實現的簡單圖片爬蟲RxJava爬蟲
- SparkSQL部署與簡單使用SparkSQL
- RxJava 知識梳理(2) RxJava2 操作符實戰RxJava
- 簡單記錄一下 laravel-swoole 的基本使用Laravel
- python的安裝與簡單使用Python
- Promise 基本方法的簡單實現Promise
- JDBC入門與簡單使用JDBC
- Git使用總結(一):簡介與基本操作Git
- MySQL基本簡單操作01MySql
- Flutter Stream 簡介及部分操作符使用Flutter
- 關於 RabbitMQ 的安裝與簡單使用MQ
- Mac下PostgreSQL的安裝與簡單使用MacSQL
- Go 原生 RPC 與 APRC 的簡單使用GoRPC
- css中的:before與:after的簡單使用CSS
- 不簡單的基本資料型別資料型別
- Redis叢集搭建與簡單使用Redis
- 雜記:Git與Github簡單使用Github
- 【填坑往事】使用Rxjava2的distinct操作符處理自定義資料型別去重的問題RxJava資料型別
- UML簡單介紹(十二)——活動圖基本概念與解析
- RxJava2原始碼分析(一):基本流程分析RxJava原始碼