Hướng dẫn RxJava: Tìm hiểu về Observables và Observers

Hi anh em, tiếp tục với Seri về RxJava nhé.

bài trước, mình đã giới thiệu sơ qua về Reactive Programming là gì, cũng như tầm quan trọng của việc nắm bắt và hiểu biết về nó. Bài này chúng ta sẽ bắt đầu đào sâu hơn về Reactive programming, mà cụ thể ở đây là RxJava.

Trước hết chúng ta sẽ tìm hiểu về 2 khái niệm quan trọng bậc nhất trong Rx: ObservablesObservers.

[toc]

Observables và Observers? Gì đây ta?

Trong RxJava có 2 khái niệm mà ta bắt buộc phải biết và nắm rõ, đó là Observables và Observers. Chúng như là 1 đôi bạn không thể tách rời trong thế giới Rx.

Observables

Observable là những thứ có thể phát ra dữ liệu, hay có thể gọi nôm na là nguồn phát dữ liệu. Nó có nhiệm vụ thông báo cho những gì đang theo dõi nó (mà sau này chúng ta sẽ biết: Observer) mỗi khi có dữ liệu mới nhất. Ta gọi việc “thông báo” này là “EMIT”

Observers

Song song cùng khái niệm Observable, ta có Observer.

Observer sẽ là những thứ theo dõi Observable. Có nghĩa là mỗi khi Observable “EMIT” dữ liệu, Observer sẽ nhận được dữ liệu đó và xử lý chúng. Ta gọi sự “theo dõi” này là “SUBSCRIBE”.

Observable và Observer đầu tiên của bạn

Mình sẽ mô tả các kiến thức của seri này thông qua 1 dự án Android. Tất nhiên không chỉ có Android mới có thể sử dụng RxJava. Nhưng mình thích nên mình sẽ dùng nó để mô tả các ví dụ 😀

Chuẩn bị: Import thư viện RxJava 2

Mình sẽ implement thư viện RxJava trong file build.gradle như sau:

implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'

Ok, mọi chuẩn bị đã xong xuôi, giờ mình sẽ tạo 1 Observable.

Observable đầu tiên

Có nhiều cách để tạo ra các Observable. Đây là 1 ví dụ:

Observable<String> observable = new ObservableCreate<String>(new ObservableOnSubscribe<String>() {
            @Override
            public void subscribe(@NonNull ObservableEmitter<String> emitter) throws Exception {
                emitter.onNext("cungdev.com");
                emitter.onNext("hello anh em");
                emitter.onComplete();
            }
});

Ở đây mình đã tạo 1 observable bằng interface ObservableCreate. Có 3 điều ta cần chú ý.

  1. Observable mình tạo ra có kiểu Observable<String>. Tức là observable sẽ phát ra (Emit)  các dữ liệu có dạng String.

  2. Để theo dõi (Subscribe) Observable<String> thì ta cũng cần 1 Observer chuyên để xử lý dữ liệu dạng String. Như bạn thấy ở trên, ta đã dùng 1 ObservableEmitter<String> để xử lý.

  3. Interface ObservableCreate mà mình dùng để tạo ra Observable<String> có 1 phương thức subscribe(@NonNull ObservableEmitter<String> emitter)

    Đây là phương thức được gọi mỗi khi observable của mình có 1 Observer theo dõi. Như bạn thấy, khi có 1 Observer subscribe Observable này, Observable sẽ Emit 2 giá trị: “cungdev.com” và “hello anh em” và sẽ gọi phương thức emitter.onComplete(); Mình sẽ giải thích phương thức này sau.

 

Bây giờ, nếu bạn chạy đoạn code này lên, thử đoán xem chuyện gì sẽ xảy ra. Câu trả lời là sẽ chả có gì xảy ra cả 😀 Nguyên nhân là vì chỉ khi có 1 Observer nào đó SUBSCRIBE Observable ta vừa tạo, thì Observable mới bắt đầu EMIT các giá trị.

Ở đây ta chưa tạo ra Observer nào để SUBSCRIBE Observable, vì vậy không có gì xảy ra. Bây giờ ta sẽ bắt đầu đi tạo Observer.

Observer đầu tiên

Mình sẽ tạo ra Observer như sau:

Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                System.out.println("onSubscribe");
            }

            @Override
            public void onNext(String o) {
                System.out.println("onNext " + o);
            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onComplete() {
                System.out.println("onComplete");
            }
};

Sau khi đã tạo xong Observer, mình sẽ cho nó SUBSCRIBE Observable ở trên:

observable.subscribe(observer);

Lúc này, khi chạy ứng dụng lên mình sẽ thấy xuất hiện các dòng log:

System.out: onSubscribe
System.out: onNext cungdev.com
System.out: onNext hello anh em
System.out: onComplete

Giải thích

Như mình đã nói ở phần tạo Observable, trong ví dụ này, mỗi khi có 1 Observer SUBSCRIBE Observable, nó sẽ EMIT 2 String “cungdev.com” và “hello anh em”, sau đó gọi đến phương thức onComplete.

Observable EMIT dữ liệu bằng cách nào? Bằng cách gọi phương thức onNext của Observer.

Observer mình tạo ra đã xử lý để tiếp nhận và log ra các giá trị phát ra từ Observable. Hãy nhìn vào phương thức onNext:

@Override
public void onNext(String o) {
   System.out.println("onNext " + o);
}

Khi Obervable không muốn EMIT thêm các giá trị đến 1 Observer nào đó, nó sẽ gọi phương thức onComplete của Observer đó

emitter.onComplete();

Và phương thức onComplete được chúng ta định nghĩa khi tạo Observer như sau:

@Override
public void onComplete() {
    System.out.println("onComplete");
}

Kết quả là chúng ta đã có được những dòng log ở trên 😀

Tổng kết

Observable và Observer là 2 khái niệm song hành cùng nhau trong thế giới Rx.

Một observer subscribe 1 observable để tiếp nhận dữ liệu. Còn 1 observable gửi dữ liệu đến các observer của nó bằng cách gọi các phương thức của Observer.

Các phương thức mà Observer có là:

  1. onNext – Khi có 1 dữ liệu phát ra từ Observable
  2. onComplete – Khi không còn dữ liệu nào phát ra từ Observable
  3. onError – Khi có lỗi xảy ra và Observable không thể phát ra dữ liệu nữa. Sẽ có 1 bài riêng để nói về cái này.
  4. onSubscribe – Khi observer bắt đầu SUBSCRIBE observable.

OK, mình nghĩ chừng này thông tin là đủ để các bạn hiểu sơ bộ về Observables và Observers rồi. Hẹn gặp lại trong các bài tiếp theo.

Hướng dẫn RxJava: Giới thiệu

Chào mọi người, hôm nay mình sẽ quyết định viết 1 seri về chủ đề Reactive Programming, cụ thể ở đây là RxJava. Đây là thư viện mà có lẽ rất rất nhiều dự án Android đã đang và sẽ sử dụng (mặc cho sự phát triển và cải thiện không ngừng của Kotlin Coroutine, Flow :D). Vì vậy mình quyết định viết seri này. Mục tiêu hướng đến của seri này là những anh em dev chưa tiếp cận hoặc mới tiếp cận và muốn tìm hiểu thêm với Reactive Programming, cụ thể là RxJava. OK. Start thôi.

[toc]

Vậy Reactive Programming là cái cóc khô gì?

Reactive Programming là 1 mô hình lập trình liên quan đến luồng dữ liệu và sự thông báo khi có sự thay đổi về dữ liệu. WTF? Nói cái gì thế??? Nghe không hiểu mô tê gì.

Để dễ hiểu hơn thì hãy cùng mình xét một bài toán đơn giản: Cộng 2 số nguyên.

Với cách lập trình truyền thống, bài toán sẽ được giải như sau:

void normalAddition() {
    int a = 1;
    int b = 2;
    int sum = a + b;
    Log.d(TAG, "Ket qua: "+ sum);
}

Khi chạy hàm này thì kết quả sẽ thu được là:

Ket qua: 3.

OK không vấn đề gì.

Giờ ta hãy thay đổi hàm normalAddition này một chút, ta sẽ cập nhật giá trị cho biến A và kiểm tra lại kết qủa của biến sum:

void normalAddition() {
    int a = 1;
    int b = 2;
    int sum = a + b;
    Log.d(TAG, "Ket qua: "+ sum);
    a = 3;
    Log.d(TAG, "Ket qua: "+ sum);
}

Khi chạy lại thì được kết quả:

Ket qua: 3

Ket qua: 3

Như vậy ta thấy vấn đề là sum không được cập nhật giá trị mặc dù a đã được cập nhật.

Còn đối với Reactive programming, khi biến a thay đổi thì biến sum cũng sẽ được thông báo về sự thay đổi này, và có hành động xử lý, dĩ nhiên là update lại giá trị rồi :D.

Hãy hình dung như ở trang tính excel, khi bạn update giá trị của a, thì giá trị của sum cũng sẽ được tự động update theo vậy.

Nói tóm lại Reactive programming là mô hình lập trình mà trong đó, mọi sự thay đổi của 1 đối tượng đều được thông báo đến những đối tượng đang theo dõi nó. Như ở ví dụ trên là sum đang theo dõi ab.

 

RXJava

RxJava là một thư viện hỗ trợ Reactive programming viết riêng cho Java. Rõ ràng rồi, chúng ta đâu cần chế tạo lại cái bánh xe, cũng đủ thời gian để implement từng đối tượng, cho chúng theo dõi nhau theo 1 cách thủ công được. Vậy ta cần 1 thư viện hỗ trợ ta điều đó, thư viện này là RxJava.

Trong seri này ta sẽ tìm hiểu các tính năng hữu ích nhất của RxJava để sử dụng trong quá trình phát triển. Mình cũng sẽ đưa ra từng use case cho từng tính năng để các bạn dễ hình dung.

Bài viết tiếp theo mình sẽ giới thiệu về 2 khái niệm cơ sở của RxJava và cách chúng ta làm việc với chúng.

Cảm ơn đã đọc bài viết. Hẹn gặp lại.

[toc]