Sử dụng RxJava, RxAndroid và Retrolamda

Reactive Programming là lập trình với các dòng dữ liệu bất đồng bộ. Sau khi đọc hàng chục bài viết, cày nát hàng trăm đoạn mô tả định nghĩa thì cuối cùng mình cũng "chưa hiểu gì". Tất cả những gì mình biết về Reactive Programming chỉ có vậy (facepalm).

Đọc bài chán quá nên mình chuyển hướng sang thực hành và có lẽ nhờ nó minh sẽ giác ngộ ra chân lý cũng nên (haha) . Dù sao thì tuy không hiểu lý thuyết nhưng có làm thực hành vẫn hơn là không làm gì cả.

Bài này mình ghi lại những ví dụ khi làm việc với RxJava, RxAndroidRetrolambda để xem cách nó hoạt động ra sao.

Các thành phần cơ bản của Rx Programming đó là ObserverablesSubscribers. Một Observerable phát ra các items, một Subscriber lắng nghe và xử lý các items đó khi nó được phát ra.

CÀI ĐẶT

Trước hết bạn muốn làm việc với Lambda Expression trên Android studio bạn phải cài đặt Retrolambda theo bài viết này.

Sau đó cài đặt RxJavaRxAndroid bằng gradle dependencies:

compile 'io.reactivex:rxandroid:1.1.0'
compile 'io.reactivex:rxjava:1.1.0'

Thêm nữa để làm việc với View thì bạn cần thêm dependency của thư viện RxBinding

compile 'com.jakewharton.rxbinding:rxbinding:0.3.0'

Bạn sync lại gradle và bắt đầu viết thử một số đoạn mã nào.

View Click Event

RxBinding là thư viện hỗ trợ giúp viết các sự kiện theo cách của Reactive Programming.

Thay vì bạn bắt sự kiện click của một Button bằng cách thông thường

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                    .setAction("Action", null).show();
            }
        });

thì bạn có thể dùng RxView của RxBinding:

     RxView.clicks(fab)
            .subscribe(v->Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
            .setAction("Action", null)
            .show());

Filter số chẵn

Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
            .filter(i -> i % 2 == 0)
            .subscribe(i -> Log.v("Result", "Even Numbers = [ " + i + " ]"));

Observerable cung cấp method just() dùng để convert các objects, lists, mảng objects, vào các Observerables và phát ra các objects đó.

Kết quả khi bạn xem logcat sẽ như sau:

01-24 20:52:25.069 31326-31326/com.framgia.lupx.rxexample V/Result: Even Numbers = [ 2 ]
01-24 20:52:25.069 31326-31326/com.framgia.lupx.rxexample V/Result: Even Numbers = [ 4 ]
01-24 20:52:25.069 31326-31326/com.framgia.lupx.rxexample V/Result: Even Numbers = [ 6 ]
01-24 20:52:25.069 31326-31326/com.framgia.lupx.rxexample V/Result: Even Numbers = [ 8 ]
01-24 20:52:25.069 31326-31326/com.framgia.lupx.rxexample V/Result: Even Numbers = [ 10 ]

Lặp với forEach

    Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
            .forEach(i -> Log.v("Iterating", "" + i));

Kết quả:

01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 1
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 2
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 3
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 4
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 5
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 6
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 7
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 8
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 9
01-24 21:06:02.466 8438-8438/com.framgia.lupx.rxexample V/Iterating: 10

Thực hiện GroupBy

Observable.just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
            .groupBy(i -> i % 2 == 0)
            .subscribe(grouped ->
                grouped.toList()
                    .subscribe(integers -> {
                        Log.v("Result", integers + "Even(" + grouped.getKey() + ")");
                    }));

Kết quả:

01-24 21:18:42.838 19088-19088/com.framgia.lupx.rxexample V/Result: [1, 3, 5, 7, 9]Even(false)
01-24 21:18:42.838 19088-19088/com.framgia.lupx.rxexample V/Result: [2, 4, 6, 8, 10]Even(true)

Chọn N phần tử đầu tiên

Observable.just(1,2,3,4,5,6,7,8,9,10)
            .take(5)
            .subscribe(i->Log.v("Result",""+i));

Kết quả:

01-24 21:23:52.080 22941-22941/com.framgia.lupx.rxexample V/Result: 1
01-24 21:23:52.080 22941-22941/com.framgia.lupx.rxexample V/Result: 2
01-24 21:23:52.080 22941-22941/com.framgia.lupx.rxexample V/Result: 3
01-24 21:23:52.080 22941-22941/com.framgia.lupx.rxexample V/Result: 4
01-24 21:23:52.080 22941-22941/com.framgia.lupx.rxexample V/Result: 5

First

    Observable.just(1,2,3,4,5,6)
            .first().subscribe(i->Log.v("Result",""+i));

    Kết quả: Result: 1

Last

    Observable.just(1,2,3,4,5,6)
            .last().subscribe(i->Log.v("Result",""+i));

    Kết quả: Result: 6

Distinct

Observable.just(1,2,3,1,2,3,1,2)
            .distinct()
            .subscribe(i->Log.v("Result",""+i));

Kết quả thu được 3 số 1,2,3

01-24 21:31:08.465 28400-28400/com.framgia.lupx.rxexample V/Result: 1
01-24 21:31:08.465 28400-28400/com.framgia.lupx.rxexample V/Result: 2
01-24 21:31:08.465 28400-28400/com.framgia.lupx.rxexample V/Result: 3

Map

Toán tử map() giống như là phép ánh xạ trong toán học. Giả sử mình dùng phép bình phương.

Observable.just(1,2,3,4)
            .map(i->i*i)
            .subscribe(i->Log.v("Result",""+i));

Kết quả thu được lần lượt các số 1,4,9,16

Bạn có thể sử dụng phép map nữa để convert ngược lại giá trị ban đầu

Observable.just(1,2,3,4)
            .map(i->i*i)
            .map(i->Math.sqrt(i))
            .subscribe(i->Log.v("Result",""+i));

Kết quả là : 1,2,3,4

Tạm thời mình giới thiệu một số method mình hiểu thế đã. Mình sẽ cập nhật thêm các method khác và sẽ viết 1 bài chi tiết về Reactive Programming với RxJava, RxAndroid khi nào mình hiểu về nó. (haha)

Github: RxExample