07/09/2018, 17:03

RxSwift: Bài 4 - Subjects (Part 1) - PublishSubject

RxSwift: Bài 4 - Subjects (Part 1) - PublishSubject 1. Đặt vấn đề Ở ba bài trước, bạn đã biết observable là gì? Làm sao để tạo ra nó, làm sao để subscribe nó, làm sao để dispose khi đã subscribe xong. Trong thực tế, ta muốn add new values vào observable at runtime mà sau đó sẽ emit đến ...

RxSwift: Bài 4 - Subjects (Part 1) - PublishSubject

1. Đặt vấn đề
Ở ba bài trước, bạn đã biết observable là gì? Làm sao để tạo ra nó, làm sao để subscribe nó, làm sao để dispose khi đã subscribe xong.

Trong thực tế, ta muốn add new values vào observable at runtime mà sau đó sẽ emit đến subscribers. Cái ta thực sự cần đó là cái gì đó hoạt động như một observable lẫn observer. Và cái đó chính là Subject. Trong bài này ta sẽ học về các loại subjects khác nhau, cách hoạt động với từng phần và lý do tại sao bạn lại chọn nó dựa trên những trường hợp phổ biến nhất.

Trước khi vào từng ví dụ cụ thể, mình sẽ ví dụ một loại subject cho các bạn dễ hình dung:

Ta tạo một PublishSubject. Nó sẽ nhận thông tin dữ liệu rồi quay ngược ra phát cho những subscribers của nó. Sau khi nó được khởi tạo, nó đã sẵn sàng nhận dữ liệu:
alt text

H ta truyền dữ liệu cho nó, ta sẽ truyền một dữ liệu cho nó trước
alt text

Và đây là kết quả:
alt text

Nhưng chưa print ra được gì hết bởi vì chưa có ai subscribe nó hết, tạo 1 subscribe cho nó:
alt text

Theo các bạn, có in được gì không? Câu trả lời là không. Tại sao? Mình sẽ trả lời ở phần dưới, thay vào đó mình sẽ làm một đoạn code để các bạn tự đoán tại sao.
alt text

Đây là kết quả:
alt text

2. Các loại Subject
Subject là gì? Mình chỉ nhắc lại, subjects hoạt động như cả observable lẫn observer, như ví dụ trên, bạn có thể thấy nó nhận tín hiệu ở .next events và truyền tín hiệu này đến subscribe của nó. Có 4 loại subjects:

1. PublishSubject: Bắt đầu là rỗng và chỉ phát tín hiệu mới (onNext) đến subscribe
2. BehaviorSubject: Bắt đầu với một giá trị khởi tạo và phát tín hiệu khởi tạo này. (nếu không nhận đc tín hiệu nào) và nếu có giá trị gần nhất thì nó sẽ phát giá trị này đến các subscribers của nó.
3. ReplaySubject: Tương tự với BehaviorSubject nhưng mà nó có thêm bộ đệm với số lượng nhất định. ReplaySubject sẽ phát ra nhiều giá trị gần nhất dựa trên số lượng bộ đệm này.
4. Variable: Lớp này wrap 1 BehaviorSubject, lưu giữ giá trị hiện tại như là trạng thái của nó và phát ra giá trị gần nhất/ khởi tạo đến những subscribers của nó

Nào bây giờ ta bắt tay phân tích từng thằng.

3. PublishSubject
PublishSubject được dùng khi bạn chỉ muốn subscribe để nhận những sự kiện ngay tại thời điểm bạn bắt đầu đăng kí

Trở lại ví dụ ở đầu bài, PublishSubject chỉ phát ra đến những subscribers hiện tại. Do đó nếu bạn chưa subscribe khi có gì đó đã được add trước đó, bạn sẽ không nhận được nó.

Hay xem sơ đồ dưới đây:
alt text

Dòng số 1 là PublishSubject, dòng số 2, số 3 là những subscribers. Mũi tên hướng lên của subscriptions, mũi tên hướng xuống là emit ra events.

Subscriber đầu tiên đăng kí sau 1) nên nó không nhận đc event này mà chỉ nhận được event 2) và 3). Subscriber thứ hai join sau 2) nên nó chỉ nhận được 3).

Bây giờ, quay lại code, ta sửa code một chút để dễ nhìn và thêm vào 1 subscription thứ 2, như sau:
alt text

Kết quả thu được như dự đoán, chỉ có sub01 nhận được event thứ 2.
alt text

Bây giờ mình thêm một dòng code vào, để có event mới:
alt text

Và kết quả là:
alt text

Nếu bây giờ bạn lấy subscription đầu tiên và dispose nó đi rồi add thêm new event, chỉ có sub02 có giá trị. Các bạn thử đi cho hiểu.

Cái quan trọng nhất ở đây là: Khi một PublishSubject nhận event .completed hay là .error aka event stop, nó sẽ ngưng phát event đế những new subscriber mới cũng như không phát event nữa. Tuy nhiên, nó vẫn sẽ phát event stop đến các subscribers trong tương lai. Xem code dưới đây:

alt text

Có rất nhiều thứ rất hay ở đây:

  1. Thứ nhất, mình dispose() sub01 trước khi để subject nhận event thứ 3
  2. Mình cho subject nhận event thứ 3 ("Third thing")
  3. Sau đó mình .complete()
  4. Tiếp theo mình phát tiếp tín hiệu thứ 4
  5. Mình tạo ra hai subscription, ở đây mình xin giải thích kĩ một chút:

    a. Trong cái sub03, mình chỉ để { event mà không có onNext tức là nó sẽ phát tất cả các event, mà event thì chỉ có riêng onNext mới có element. Cho nên đoạn này mình dùng nil-coalescing để unwrap cái optional này. Nếu mà là event onNext thì lấy element, ko thì lấy các event kia.
    b. Trong cái sub04 thì cũng tương tự sub03, có điều mình dùng $0 sẽ tiện hơn, thay cho việc phải gọi tên cụ thể ra.

Kết quả sẽ là:
alt text

Thực ra thì tất cả các loại subject một khi đã chấm dứt cũng sẽ phát ra event stop cho các subscribers tương lai. Mình thấy cũng hay khi mà không chỉ biết đc nó đã kết thúc mà còn thông báo cho những đứa tiếp là mình không còn emit nữa.

Đôi khi, ta cũng muốn biết những giá trị trước khi mình subscription. Đó là lý do mình có những phần khác.

0