Lập trình reactive không phải là một khái niệm mới, nó đã tồn tại trong thời gian khá dài. Tuy nhiên không phải lập trình viên nào cũng muốn học về nó. Nếu bạn đang đọc bài này, bạn ít nhiều quan tâm đến nó. Khi đến 1 trình độ nào đó, bạn sẽ thấy các vấn đề xoay quanh lập trình tuần tự liên quan đến tính bất đồng bộ của chương trình, từ phía web, ứng dụng, server. Do vậy nhu cầu xử lý tính bất đồng bộ của chương trình là cần thiết.
Lịch sử ra đời từ 1 nhóm của Microsoft, muốn xử lý các vấn đề này. Năm 2009 họ tạo ra 1 nền tảng cung cấp cho .Net, gọi là Rx. Sau này nó được open source, các bạn có thể xem thêm tại đây: https://reactivex.io.
Biểu tượng cho dự án Rx có tên là Volta – 1 con lươn điện!
Chúng ta sẽ lần lượt tìm hiểu các khái niệm của “lươn điện”: observables, operators và schedulers. Nào chúng ta cùng tìm hiểu nào!
Observables
Một lớp Observable<T> cung cấp cho Rx khả năng tạo ra 1 chuỗi các sự kiện không đồng bộ, tại bất cứ thời gian nào, mà các lớp khác có thể đăng ký lắng nghe được. Nghĩa là có thể nhiều lớp cùng đăng ký lắng nghe(observers) các sự kiện xảy ra trong thời gian thực. Observable có thể hiểu đơn giản là 1 cái trạm phát sóng, và các quan sát viên(giống như cái radio) gọi là observers, có thể lắng nghe 1 trong 3 loại sự kiện:
- Một next event: là sự kiện mới nhất, đây là cách observers nhận dữ liệu.
- Một completed event: nghĩa là sự kiện thành công, nghĩa là trạm phát observable đã hoàn thành công việc của mình và không phát ra thêm tín hiệu nào nữa.
- Một error event: nghĩa là phát ra 1 lỗi và sẽ không phát thêm sự kiện nào nữa.
Nhấn mạnh: Hãy lẩm bẩm trong miệng 2 khái niệm mới đến khi thuộc lòng và hiểu bản chất:
Observable – trạm phát tín hiệu
observers – các quan sát viên thu tín hiệu
Ví dụ, 1 chuỗi phát ra các giá trị nguyên theo thời gian thực được mô tả ở hình sau:
Ngoài số nguyên, bạn có thể phát ra bất cứ thứ gì bạn muốn. Và một trạm phát có thể có nhiều quan sát viên, do vậy bạn thích bao nhiêu observer cũng được, mà không cần phải kế thừa hay ủy quyền gì cả.
Để hiểu hơn, chúng ta xét tình huống cụ thể, khi ứng dụng ios đang tải xuống 1 file lớn trên mạng. Các sự kiện của chuỗi phát ra như sau:
- File bắt đầu tải, bắt đầu quan sát dữ liệu đến
- Sau đó, chúng ta liên tục nhận được các phần dữ liệu tải về
- Nếu có lỗi kết nối mạng, quá trình tải xuống dừng do lỗi
- Nếu không file tải thành công và quá trình kết thúc thành công
Follow code sẽ như sau:
API.download(file: “https://www…”)
.subscribe(onNext: { data in
… nối các phần của file lại
},
onError: { error in
… hiển thị lỗi cho người dùng
},
onCompleted: {
… sử dụng file download xong
})
Xem tiếp…
Trong đoạn code trên, API.Download sẽ trả về 1 Observable<Data>, phát ra chuỗi các data gửi về qua mạng. Bạn đăng ký nghe các sự kiện ở onNext, ở trên là nối các phần của file tải về và lưu tạm vào ổ đĩa. Bạn đăng ký lắng nghe lỗi ở onError, có thể hiển thị lỗi cho người dùng biết. Bạn đăng ký sự kiện tải file thành công ở onCompleted, có thể mở file, hay làm bất cứ thứ gì mà logic app của bạn muốn.
Infinite observable sequences
Hay còn gọi là chuỗi quan sát vô hạn. Không giống như ví dụ trên, chúng ta sẽ có những tính huống quan sát các sự kiện vô hạn. Ví dụ khi bạn muốn quan sát sự kiện thiết bị người dùng thay đổi khung hình ngang hay dọc.
Chuỗi này là không có kết thúc, bạn chỉ biết thời điểm bắt đầu khi bạn quan sát, và luôn xử lý nó cho đến khi ứng dụng kết thúc.
Trong RxSwift, code được mô tả như sau:
UIDevice.rx.orientation
.subscribe(onNext: { current in
switch current {
case .landscape:
… sắp xếp giao diện người dùng ngang
case .portrait:
… sắp xếp giao diện người dùng dọc
}
})
Xem tiếp…
Lưu ý đoạn code trên là hư cấu(không chạy được), để mô tả việc rx phát ra chuỗi phát thiết bị đang ở chế độ ngang hay dọc. Tuy nhiên chúng ta sẽ dễ dàng biến điều hư cấu trên thành thật bằng cách tự viết được đoạn code cho nó trong các bài tiếp theo.
Operators
Khác với toán tử thông thường, các toán tử trong Rx cung cấp khả năng mở rộng để giải quyết các phương thức tính toán trừu tượng, giải quyết các vấn đề phức tạp của bất đồng bộ. Bởi vì chúng có khả năng tách biệt và đồng bộ, nên gọi là toán tử. Chúng có khả năng nhận đầu vào không đồng bộ, kết hợp với nhau tạo thành 1 bức tranh lớn hơn về logic app.
Ví dụ phép tính số học thông thường (5 + 6) * 10 – 2. Chúng ta vận dụng thứ tự ưu tiên trong ngoặc trước, nhân chia trước, cộng trừ sau để đưa ra kết quả cuối cùng. Tương tự trong Rx, các toán tử cũng được kết hợp như vậy, theo thứ tự ưu tiên xác định, cuối cùng đưa ra kết quả.
Ví dụ lại cách Rx lắng nghe sự kiện thiết bị thay đổi chiều:
UIDevice.rx.orientation
.filter { value in
return value != .landscape
}
.map { _ in
return “Portrait is the best!”
}
.subscribe(onNext: { string in
showAlert(text: string)
})
Xem tiếp…
Mỗi khi thiết bị xoay ngang hay dọc thì rx sẽ phát ra sự kiện đó.
Đầu tiên chúng ta dùng toán tử filter để lọc những giá trị không phải là landscape. Tiếp theo chúng ta dùng toán tử map để trả về 1 đoạn string thông báo “Portrait is the best!”
Schedulers
Hiểu sơ sơ nó na ná giống bộ lập lịch của Apple, tuy nhiên chúng ta sẽ nghiên cứu chúng sau khi đã hoàn thành các kiến thức cơ bản về RxSwift.
- Trong hình ảnh trên, phần network màu xanh biển sẽ chạy trên NSOperation based scheduler
- Phần data binddings màu xanh lá cây chạy trên bộ lập lịch background GDC
- Phần màu đỏ UI để cập nhật các sự kiện UI trên main thread
Trông có vẻ đơn giản đúng không? Nhưng tạm thời chúng ta sẽ quan tâm nó vào các bài sau cùng nhé.
Kiến trúc ứng dụng
Chúng ta có thể chọn lựa bất kỳ loại kiến trúc nào cho RxSwift, có thể MVC – kiến trúc base của apple. Hoặc bạn có thể dùng MVVM – để giải quyết các vấn đề của MVC. Nó là sự chọn lựa của bạn.
Điều đó có nghĩa là bạn cũng có thể dùng RxSwift với những tính năng mới của app, không bắt buộc phải dùng từ đầu.
Có 1 điều là, bằng kinh nghiệm thực tiễn thì MVVM và RxSwift là 1 sự kết hợp tuyệt vời. Sau này có thể bạn ngầm hiểu dùng RxSwift thì mặc định dùng MVVM để triển khai project của mình.
View Model sẽ cho phép bạn hiển thị các thuộc tính quan sát được, bạn có thể liên kết trực tiếp với UI nên dễ dàng cho việc viết mã.
Tuy nhiên tất cả các ví dụ sau này chúng ta sẽ dùng MVC cho việc học RxSwift đơn giản nhất.
Vậy là chúng ta đã hiểu một phần về RxSwift. Trong bài tiếp theo chúng ta sẽ nghiên cứu cách cài đặt môi trường RxSwift cho việc nghiên cứu bộ môn Rx tuy cũ nhưng lại hay ho này.