上个星期看到 trello
招聘远程 android 工程师,其中 trello
说道他们是 RxJava
的重度用者。
RxJava
? 什么是 RxJava
。
RxJava
是 Reactivex 库的一个扩展。
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、适用于处理并发问题
RxAndroid 是 RxJava
的一个特别版,主要是提供了可设置计算的所在线程以及更新 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
变成 AppObservable
, ViewObservable
的这个 text()
方法已经移到 WidgetObservable
这个类下面等等。
不过四篇文章的思想还是在的,变的只是类和方法的改动,所以不能直接拷贝代码到 IDE 里面去运行,不然都是报错,然后就怀疑这是什么鬼玩意啊,就不再深究下去了。
接下来我们来体验一番基于事件的函数响应式编程。我们来实现一个这样的一个需求,点击复选框,检查输入框是否为空,效果如图:
我们平时的话一般都是给这三个控件设置事件监控,声明一个复选框选中标识 flag,然后在监控控件的回调函数去判断,代码大概是这个样子:
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
的话,就是这个样子:
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、基于事件的可组合模式(以上就是把复选框的选中事件和输入框的输入事件组合在一起)
上面的例子我没有理会错误的处理和完成的处理,其实我们还可以这样做:
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 然后去下载图片并显示:
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:这块领域比较新,可参考的文献也较少,有,也是英文居多,本人精力有限,暂只能领会这么多,也难免有错误理解之处,如有,望帮忙校正,谢谢。