RxAndroid初步探究(一)

RxJava 更新速度很快,本文已严重过时

RxJava 更新速度很快,本文已严重过时

RxJava 更新速度很快,本文已严重过时

但本人没有删文章的习惯,此文仅作留念,有兴趣也可继续往下看


上个星期看到trello招聘远程 android 工程师,其中trello说道他们是RxJava的重度用者。

RxJava ? 什么是 RxJava

RxJavaReactivex 库的一个扩展。

Reactivex 又是什么? 官方是这样解释的:

ReactiveX is a library for composing asynchronous and event-based programs by using observable sequences.

It extends the observer pattern to support sequences of data and/or events and adds operators that allow you to compose sequences together declaratively while abstracting away concerns about things like low-level threading, synchronization, thread-safety, concurrent data structures, and non-blocking I/O.

总结一下特点:

1、函数响应式编程(Functional Reactive Programming)简称 FRP

2、异步

3、事件驱动(事件作为可观察序列)

4、基于观察者模式

5、组合式

6、专门出错处理

7、适用于处理并发问题

RxAndroidRxJava 的一个特别版,主要是提供了可设置计算的所在线程以及更新 UI 时可在主线程更新。

provides a Scheduler that schedules an Observable on a given Android Handler thread, particularly the main UI thread
provides base Observer implementations that make guarantees w.r.t. to reliable and thread-safe use throughout Fragment and Activity life-cycle callbacks (coming soon)
provides reusable, self-contained reactive components for common Android use cases and UI concerns (coming soon)

这块新大陆开垦的人少之又少,没猜错的话,大家几乎都是在看 Grokking RxJava 这四篇文章,其中第四篇Grokking RxJava, Part 4: Reactive Android就是讲RxAndroid的。虽然这篇文章是发表于 2014 年 10 月 8 日,但RxAndroid里面已经有很多改动,例如:AndroidObservable 变成 AppObservableViewObservable 的这个text()方法已经移到WidgetObservable这个类下面等等。
不过四篇文章的思想还是在的,变的只是类和方法的改动,所以不能直接拷贝代码到 IDE 里面去运行,不然都是报错,然后就怀疑这是什么鬼玩意啊,就不再深究下去了。

接下来我们来体验一番基于事件的函数响应式编程。
我们来实现一个这样的一个需求,点击复选框,检查输入框是否为空,效果如图:

enter image description here

我们平时的话一般都是给这三个控件设置事件监控,声明一个复选框选中标识 flag,然后在监控控件的回调函数去判断,代码大概是这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
        checkButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                needCheck = b;
                if(needCheck){
                    if(mEditText.getText().toString().equals("")){
                        okBtn.setEnabled(false);
                    }else{
                        okBtn.setEnabled(true);
                    }
                }else{
                    okBtn.setEnabled(true);
                }
            }
        });

        mEditText.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i2, int i3) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i2, int i3) {
                if(needCheck){
                    if(charSequence.toString().equals("")){
                        okBtn.setEnabled(false);
                    }else{
                        okBtn.setEnabled(true);
                    }
                }
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        });

        okBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(MainActivity.this, mEditText.getText().toString(), Toast.LENGTH_SHORT).show();
            }
        });

而我们使用RxAndroid 的话,就是这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        Observable<Boolean> needCheckObservable = WidgetObservable.input(checkButton, true).map(new Func1<OnCheckedChangeEvent, Boolean>() {
            @Override
            public Boolean call(OnCheckedChangeEvent onCheckedChangeEvent) {
                return onCheckedChangeEvent.value();
            }
        });

        Observable<OnTextChangeEvent> editTextObservable = WidgetObservable.text(mEditText, true);

        Observable.combineLatest(needCheckObservable, editTextObservable, new Func2<Boolean, OnTextChangeEvent, Boolean>() {
            @Override
            public Boolean call(Boolean aBoolean, OnTextChangeEvent onTextChangeEvent) {
                return aBoolean ? !TextUtils.isEmpty(onTextChangeEvent.text()) : true;
            }
        }).observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<Boolean>() {
                    @Override
                    public void call(Boolean aBoolean) {
                        okBtn.setEnabled(aBoolean);
                    }
                });

        ViewObservable.clicks(okBtn)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Action1<OnClickEvent>() {
                    @Override
                    public void call(OnClickEvent onClickEvent) {
                        Toast.makeText(MainActivity.this, mEditText.getText().toString(), Toast.LENGTH_SHORT).show();
                    }
                });

平时的方法,用了 45 行代码,用 RxAndroid 则是 29 行,那句什么话来着,less is more.

用代码行数去衡量一段代码的好坏? 似乎太庸俗,太傻 X 了,当然,我们不会这样去衡量。只是开个玩笑.

来,我们来看看上面的代码。

1、函数式表达
2、基于事件的可组合模式(以上就是把复选框的选中事件和输入框的输入事件组合在一起)

上面的例子我没有理会错误的处理和完成的处理,其实我们还可以这样做:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
        ViewObservable.clicks(okBtn)
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Observer<OnClickEvent>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        Toast.makeText(MainActivity.this, " 哎呀,出错了 ", Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onNext(OnClickEvent onClickEvent) {
                        Toast.makeText(MainActivity.this, mEditText.getText().toString(), Toast.LENGTH_SHORT).show();
                    }
                });

专门有出错的处理回调。

上面的例子也没有体现出异步的功能,我们再来个例子,在输入框输入一个图片 url 然后去下载图片并显示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        ViewObservable.clicks(okBtn).map(new Func1<OnClickEvent, Bitmap>() {
            @Override
            public Bitmap call(OnClickEvent onClickEvent) {
                return null;
            }
        })
        .subscribeOn(Schedulers.newThread())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Bitmap>() {
            @Override
            public void onCompleted() {
                Toast.makeText(MainActivity.this, " 图片加载完成 ", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onError(Throwable e) {
                Toast.makeText(MainActivity.this, " 哎呀,出错了 ", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onNext(Bitmap bitmap) {
                //show your bitmap
            }
        });

体验到函数响应式编程的魅力了吗? 反正我已经上瘾了,这片新的技术等着你和我去探究。

现在研究这个的人实在太少了,很少能找到交流的人,也没搜到相关的交流群,我在这里建了一个群:16703352 , 有兴趣的同学可以加一加,大家一起来探究探究哦。

可能有同学发现了,以上说的都是函数式编程的好处,那它有不好的地方吗? 当然有啦。这个下次再来探讨,有点困了,又 12 点了,我的早睡好习惯呢。

PS:这块领域比较新,可参考的文献也较少,有,也是英文居多,本人精力有限,暂只能领会这么多,也难免有错误理解之处,如有,望帮忙校正,谢谢。