RxDart
今年年初開始嘗試使用Flutter
開發android APP,期間遇到了不少的坑,但總算是有驚無險。而在做Android原生開發時,RxAndroid
讓程式碼爽到飛起。為了找回那種熟悉的感覺,特意將RxDart
引入到專案中。首先介紹一下RxDart
是什麼:
RxDart
基於ReactiveX,由Dart
標準庫中Stream
擴充套件而成,是一個為Dart語言提供響應式程式設計的庫。
如何使用
新增依賴
首先在pubspec.yaml
中新增依賴:
dependencies:
rxdart: ^0.22.1+1
複製程式碼
範例
接下來我們通過一段程式碼來看一下如何使用RxDart
Observable.just(1).listen(print);
>>>1
複製程式碼
一行完事兒?這都是什麼啊?彆著急,這只是Dart語法的特性,接下來我們將上面的程式碼進行拆分:
//建立一個被觀察者
var observable = Observable.just(1);
//建立一個觀察者
var observa = (int num) {
print(num);
};
//通過listen實現訂閱
observable.listen(observa);
複製程式碼
這下就明朗了,作為一個Android開發者,對這段程式碼充滿親切感。簡直和RxJava一抹一樣!!!
建立被觀察者
RxDart提供了很多方法供我們建立Observable,除了上文中的直接使用just工廠函式從單個值中建立
,還有以下幾種建立方法:
- 從一個Stream中建立:
Observable(Stream.fromIterable([1, 2, 3, 4, 5])).listen(print);
- 建立週期性事件:
Observable.periodic(Duration(seconds: 1), (x) => x.toString()).listen(print);
這段程式碼每隔一秒鐘列印一個整數並加一 - 從Future中建立:通過一個Future建立的Observable,會先等待Future執行完畢,完後發射資料,這個輸出資料就是Future的執行結果,如果Future沒有任何返回值,那麼輸出null。還可以
toStream
方法將Future轉換為Stream然後再建立:
Observable.periodic(Duration(seconds: 1), (x) => x.toString()).listen(print);
Future<String> asyncFunction() async {
return Future.delayed(const Duration(seconds: 10), () => "十秒後的資料");
}
Observable.fromFuture(asyncFunction()).listen(print);
複製程式碼
程式碼輸出如下:
操作符和資料變換
Rx最爽的是什麼?當然是無處不在的操作符啦!我個人覺得操作符是Rx的靈魂,關於操作符原理大家可以閱讀從原始碼檢視RxJava中的map和flatMap的用法和區別去了解。下面我們通過幾個常用的操作符學習一下RxDart的操作符使用方法:
過濾操作符
過濾操作符就是用來過濾掉Observable發射的一些資料,丟棄這些資料只保留過濾後的資料。
where
點了半天編輯器總是不自動補全Filter
竟然沒有Filter操作符號了,還好有個where 我們實現一個對奇偶進行過濾的操作:Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
.where((num) => num % 2 == 0)
.listen(print);
>>>2 4
複製程式碼
skip
如果我們想跳過前三個數字,我們可以使用skip操作符:
Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
.skip(3)
.listen(print);
>>> 4 5
複製程式碼
take
和skip操作相反,如果我們去掉後面三個資料,只輸出前面兩個資料:
Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
.take(2)
.listen(print);
<<<1 2
複製程式碼
distinct
如果我們要過濾掉原始資料裡重複的項:
Observable(Stream.fromIterable([1, 2, 2, 2, 3, 3, 4, 5]))
.distinctUnique()
.listen(print);
>>> 1 2 3 4 5
複製程式碼
變換操作符
過濾操作符就是用來過變換Observable發射的一些資料或者Observable本身,將被變換的物件轉換成為我們想要的。
map
首先說一下map
,依舊是實現一個基本的資料轉換,將數字翻倍:
Observable(Stream.fromIterable([1, 2, 3, 4, 5]))
.map((num) => num * 2)
.listen(print);
<<<2 4 6 8 10
複製程式碼
flatMap
接下來說一下flatMap
,取出一個由陣列組成的陣列中的元素:
var list1 = [1, 2, 3];
var list2 = [4, 5, 6];
var list3 = [7, 8, 9];
var listAll = [list1, list2, list3];
Observable(Stream.fromIterable(listAll))
.flatMap((listItem) => Observable(Stream.fromIterable(listItem)))
.listen(print);
<<<1 2 3 4 5 6 7 8 9
複製程式碼
concatMap
類似flatMap操作符,區別在於concatMap按次序連線而不是合併那些生成的Observables,然後產生自己的資料序列。 看看下面的程式碼:
var list1 = [1, 2, 3];
var list2 = [4, 5, 6];
var list3 = [7, 8, 9];
var listAll = [list1, list2, list3];
var changeConcatMap = (List<int> listItem) {
print("concatMap開始變換了");
return Observable(Stream.fromIterable(listItem));
};
var changeFlatMap = (List<int> listItem) {
print("FlatMap開始變換了");
return Observable(Stream.fromIterable(listItem));
};
Observable(Stream.fromIterable(listAll))
.concatMap((listItem) => changeConcatMap(listItem))
.listen(print);
Observable(Stream.fromIterable(listAll))
.flatMap((listItem) => changeFlatMap(listItem))
.listen(print);
複製程式碼
輸出結果為:
結合操作符
startWith
在資料序列的開頭插入一條指定的項:
var observable = Observable(Stream.fromIterable([1, 2, 3, 4, 5]));
observable.startWith(9).listen(print);
>>>9 1 2 3 4 5
複製程式碼
merge
使用Merge操作符你可以將多個Observables的輸出合併,就好像它們是一個單個的Observable一樣。但是可能會讓合併的Observables發射的資料交錯
Observable.merge([
Stream.fromIterable([1, 2]),
Stream.fromIterable([3, 4])
]).listen(print);
>>> 1 3 2 4
複製程式碼
combineLatest
當兩個Observables中的任何一個發射了資料時,使用一個函式結合每個Observable發射的最近資料項,並且基於這個函式的結果發射資料。
var observable1 = Observable.just(1);
var observable2 = Observable.just(2);
Observable.combineLatest([observable1, observable2], (num) => num)
.listen(print);
>>>[1,2]
複製程式碼
mergeWith
mergeWith將多個被觀察者發射的流合併成一個流。資料按照被髮送的順序傳遞
var observable1 = Observable.just(1);
var observable2 = Observable.just(5);
var observable = Observable(Stream.fromIterable([1, 2, 3, 4, 5]));
observable
.mergeWith([observable2,observable1])
.listen(print);
>>> 1 5 1 2 3 4 5
複製程式碼
結語
這只是一片RxDart使用的入門教程的。本文並未深入探討RxDart的實現原理和邏輯,因為這些原理基本和RxJava中的類似。感興趣的可以去關注我的RxJava系列的文章