誤入Android開發-Day10:RxJava的操作符(三)

影山小麥機
8 min read5 days ago

--

來聊事件流與操作符之間的關係

前言

記錄一下這是我的第101篇Medium的技術文章。從iOS的OOP世界,寫到軟體工程的工作紀錄,在職也大概快三年多,從iOS到Flutter,再到Android,OOP世界轉往FRP世界,工作面對過挑戰,曾經加班過夜,曾經要趕專案,曾經製造出無數bug。

職場上也許有很多人真的很強,對我做出來的東西覺得還好,但我覺得最重要的是自己仍在攝取與進步,把開發者的每一天做的實在,就不會困在基礎不扎實的狀態之中。

接下來我們要談的是RxJava中的操作符。

正文

如果說事件流是Rx的本體,那麼操作符就是它的靈魂,我們可以看見每一個操作符在事件流流出事件、值、物件時後面跟著的方法用以對事件流的流出的物件進行各種加工。

以下會對操作符有一些基本的介紹:

以上是RxJava在操作符上比較常見的幾類。那麼,咱們就一個一個慢慢聊。

創建數據流(Observable/Flowable)

創建數據流,就簡單而言,就是把數據直接轉為Observable,這邊可以直接用just()

Observable<String> observable = Observable.just("Hello", "RxJava");
observable.subscribe(System.out::println);

output:

Hello
RxJava

或者可以用fromArray,就直接把陣列轉成數據流:

String[] items = {"Apple", "Banana", "Cherry"};
Observable<String> observable = Observable.fromArray(items);
observable.subscribe(System.out::println);

output:

Apple
Banana
Cherry

或create(),這是一種手動發射數據的方式:

Observable<Integer> observable = Observable.create(emitter -> {
emitter.onNext(1);
emitter.onNext(2);
emitter.onComplete();
});

observable.subscribe(System.out::println);

一個一個用onNext發射。

數據轉換

這些操作符是用於轉換數據流中的數據:

常見的就map()囉:

Observable.just(2)
.map(value -> value * 10)
.subscribe(System.out::println);

output:

20

無序一對多數據轉換

用flatMap():

Observable.just("A", "B")
.flatMap(letter -> Observable.just(letter + "1", letter + "2"))
.subscribe(System.out::println);

output:

A1
A2
B1
B2

有序數據轉換

concatMap()一對多轉換(保證順序)

Observable.just("A", "B")
.concatMap(letter -> Observable.just(letter + "1", letter + "2"))
.subscribe(System.out::println);

output:

A1
A2
B1
B2

最後一個數據流轉換

用switchMap()

過濾數據

用filter()

Observable.just(1, 2, 3, 4, 5)
.filter(value -> value % 2 == 0) // 只保留偶數
.subscribe(System.out::println);

output:

2
4

取前N個數據

用take()

Observable.just(1, 2, 3, 4, 5)
.take(3)
.subscribe(System.out::println);

output:

1
2
3

合併數據流

用merge(),兩個數據流同時發射

Observable<String> observable1 = Observable.just("A", "B", "C");
Observable<String> observable2 = Observable.just("1", "2", "3");

Observable.merge(observable1, observable2)
.subscribe(System.out::println);

output:

A
1
B
2
C
3

合併並對應數據流

用zip()

Observable<Integer> observable1 = Observable.just(1, 2, 3);
Observable<String> observable2 = Observable.just("A", "B", "C");

Observable.zip(observable1, observable2, (num, letter) -> num + letter)
.subscribe(System.out::println);

output:

1A
2B
3C

錯誤處理

RxJava 的異步數據流,錯誤處理非常重要!

使用onErrorReturn() ,發生錯誤時,提供一個預設值:

Observable.just(1, 2, 0, 4)
.map(value -> 10 / value) // 這裡會因為除以 0 出錯
.onErrorReturn(error -> -1) // 這時候返回 -1
.subscribe(System.out::println);

output:

1
2
-1

線程切換

Rx最重要的特性之一:非同步處理,線程操作符下下

Observable.just("Hello")
.subscribeOn(Schedulers.io()) // 在 IO 線程執行
.observeOn(AndroidSchedulers.mainThread()) // 回到主線程
.subscribe(System.out::println);

所謂的IO(Input/Output)線程 指的是用來處理 IO 密集型操作(如網絡請求、文件讀寫、數據庫操作等)的線程。
在Anroid開發中,主線程負責UI操作,如果在主線程進行網絡請求或文件讀取,會導致 ANR(應用無回應)錯誤,因為 UI 會被阻塞。

總的來說Rx的核心概念大概有哪些呢?

五大核心事件流 (Observable, Flowable, Single, Maybe, Completable)

背壓 (Backpressure)

熱/冷數據流 (Hot Observable, Cold Observable)

✅ SubjectProcessor

操作符 (map(), flatMap(), switchMap(), filter(), merge() 等)

線程控制 (Schedulers.io(), Schedulers.computation(), AndroidSchedulers.mainThread())

這邊大致上已經提及了百分之80%了,我想接下來更多的就是實作了!
這邊有可能也會規劃一點Rx的實作篇章,比如創建了數據流之後,還可能會有需要dispose數據流的可能,這時候應該怎麼辦呢?

我想之後再陸續規劃類似的篇章出來!

尾聲

默默的,也寫大約100篇了,還記得從iOS出發時,那時趕著快速的發文,讀完語法,然後進到實作裡,在實作的篇章的時候,大概從不知道OOP到知道OOP,然後接著在iOS中打轉,然後為了找到工作,開始寫Flutter,開始解決雙平台的問題,Well,不得不承認,iOS、Flutter兩者有巨大的差別,但實作起來Flutter確實方便多了。

Android呢?我覺得摸著摸著到現在Android真的就在商業環境不同的機型中打轉,最困境的大概都是底層的不一樣。但實作起來,Ummmm,實作原理都差不了多少。

所以,我都摸的一清二楚了嗎?

Nope,我想我的文章會有這100篇,可能只是剛開始而已。我想我會耕耘在Mobile這個領域一陣子,至少這件事情我是感興趣的。手機市場會持續多久老實說我並不知道,但可以預見的未來是邏輯不滅、框架、語言不滅、思維不變。就算往後Mobile前端覆滅,相應的思維也會由自己跨到其他領域繼續帶著走。

接下來想做點SwiftUI,再回去摸摸iOS,或者找到一些Flutter之前沒有摸完整的框架來實作。做SideProject對我來說還好,但寫寫文字我還算喜歡。

--

--

影山小麥機
影山小麥機

Written by 影山小麥機

本職為Mobile工程師,熱愛分享視野,也樂意站在ChatGPT的肩膀上。訂閱小麥機,收割技術、職涯、人生的難題。

No responses yet