最近,我抽出了几个晚上的时间,把咖啡和啤酒变成了代码与文字。
引子
三个月以来,我翻译了一些关于RxJava的文章,说实话这些翻译,真的搞得我很头疼,那么现在是时候回来写点什么了。
最近,我在看两本书,《Learning Reactive Programming with Java 8》,《RxJava Essentials》,不过,没关系,我已经买到了电子版,我会在文章结尾附上网盘链接和密码,但我还是希望你将文章继续读下去,因为那是文章结尾的事。
其实关于RxJava的文章和消息远不止我们能了解到的,但又拜英语所赐,所以它看起来又没那么多。好在,国内有许多优秀的开发专家hi大头鬼hi ,BlackSwift,程序亦非猿,Drakeet,扔物线,流火枫林等等在为之做着贡献,以及简直不能更优秀的文章《给 Android 开发者的 RxJava 详解》。
但是,现在,我不得不再次做啰嗦一下,RxJava究竟会改变我们什么。
响应式编程Reactive Programming
什么是响应式编程呢?在Java程序中:
1 2 3 4 5 6 7 8 |
int a = 4; int b = 5; int c = a + b; System.out.println(c); // 9 a = 6; System.out.println(c); // 9 again, but if 'c' was tracking the changes of 'a' and 'b', // it would've been 6 + 5 = 11 |
当我们改变“a”和“b”的值时,“c”并没有改变。换句话说,“a”和“b”的改变并没有响应到“c”。这就是响应式:程序以流的形式,传递数据的改变。
那我,我们又为什么需要响应式呢?
以下翻译自《Learning Reactive Programming with Java 8》
10-15年前,对于网站开发来说,最平常的日常工作就是进行维护和缩短响应时间,那么今天,一切程序都应该保证七天二十四小时不间断运行,并且能够极快的做出响应;如果你的网站响应慢或者宕机,那么用户将会对你们真爱一秒变备胎,转而选择其他网站服务。当今的慢意味着不可用甚至是有故障的。如今的互联网是在和大数据打交道,所以我们需要快速的处理数据。
过去的几年中HTTP错误已经不是什么新鲜事了,但是现在,我们不得不进行容错机制,还要提供用户易读以及合理的消息更新。
在过去,我们写简单的桌面应用,但如今我们写能够做出快速响应的Web应用。多数情况下,这些应用要与大量的远程服务器进行数据传递。
如果我们想让自己的软件保持竞争性,就不得不实现这些新需求,所以,换言之就是我们应该这样做:
- 模块的/动态的:用这种方式,我们就能够拥有一个七天二十四小时的系统了,因为这些模块能够在不停止整个系统的情况下进行脱机和联机。另外,随着系统的不断庞大,还能帮助我们更好地组织应用结构,同时还能管理底层代码。
- 可扩展的:用这种方式,我们就能够处理大量的数据和用户请求了。
- 容错性:用这种方式,能够为用户提供稳定的系统。
- 响应式:这不仅意味着快速,还意味着可用性强。
让我们思考如何实现它:
- 如果我们的系统是事件驱动型的,那就把它模块化。我们可以将系统分成多个彼此之间通过通知进行交互的微服务/组件/模块。这样,我们就能够以通知为代表,响应系统的数据流了。
- 可扩展意味着能够应对日益增长的数据,在负载的情况下不会崩溃。
- 对故障/错误做出及时的响应,能够提高系统的容错性。
- 响应意味着对能够对用户操作及时的做出反应。
如果应用是事件驱动型的,那么,它就能够解耦成多个自包含组件。这能够帮我们更好的实现扩展性,因为我们总是可以在不停掉或者打断系统的情况下添加新组建或者移除旧组件。如果错误和故障传递给正确的组件,把它们当做通知来处理并作出响应,那么应用能变得更具有容错性和弹性。所以,如果把系统构建成事件驱动型的。我们可以更容易的实现扩展性和容错性,而且一个具有扩展性,低耦合和防错的应用能够快速的响应用户操作。
Reactive Manifesto文档定义了我们刚刚提到的四点响应式准则。每一个响应式系统都应该是消息驱动型(事件驱动型)的。这样它不仅能变得低耦合,而且扩展性和容错性将更高,这就意味着它可靠和具有响应式。
要注意的是,Reactive Manifesto只是描述了一个响应式系统,并不是对响应式编程的定义。当然,你也可以不使用任何响应式类库或者语言,打造一款弹性可扩展,具有消息驱动的响应式应用。
应用程序中数据的变化,以通知的方式传递给正确的Handler。所以,使用响应式构造应用是符遵循Manifesto最简单的方式。
回调地狱
如果你是一个能够时刻保持头脑清醒,逻辑清晰和思维缜密的人,是个Callback
高手,善用并且能够用好FutureTask
。
那么在Android中你的代码可能会频繁的使用async
+callbacks
,或者service composition
+ error handing
。
那么关于异步回调的逻辑,你会写成这样getData(Callback<T>)
、这样Future<T> getData()
,还是这样Future<List<T>> getData()
,甚至这样Future<List<Future<T>>> getData()
,嗷!拜托,我简直不能再举例下去了,这简直就是Callback Hell,这样的程序或许写起来很舒服,但是如何测试和维护呢。
如果哪天你的程序出了问题而必须马上修复,但你却不能马上赶来或者需要别人协助(这在很多公司是很常见的),或者当他人在review你的代码时,那么,是时候拿出这张图了。
然而使用RxJava的操作符,我们可以避免这些烦人甚至糟糕的回调,让结构和思路看起来更清晰,通过组合API,只需要约定最终的结果Observable<T>
就行了。
并且scheduler
的出现,不仅解放了线程的切换,让UI线程与工作线程间的跳转变得简单,而且,它的API很丰,也提供了很多使用场景的建议,比如,适用计算任务的Schedulers.computation( );处理密集IO任务的Schedulers.io( );以及Schedulers.trampoline( )能够有效避免StackOverflowError,所以非常适合函数的递归调用。好了,我不再举例了,因为官方文档已经给出了很详细的解释了,但是值得一提的是,如果使用Schedulers
的工厂方法创建的Worker
,一旦任务执行完毕,都应该调用worker.unsubscribe( )
方法,然后转向之前定义的Scheduler
实例上来。
当然RxJava的出现并不仅仅是为了解决回调地狱的。
这是我通过学习和不断地练习,一路走来很辛苦,总结的一些经验,分享给大家:
1 . error handling
3 . caching (roation)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); /*.cache()操作符: 当第一个subscribe订阅的时候,才会连接原始Observable,缓存事件,重发给后续订阅的subscribe 值得注意的事,它和使用了.replay()操作符的ConnectableObservable的不同。 另外,为了避免内存开销,不建议缓存大量事件*/ cacheObservable = weatherManager.getWeather().cache(); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); cacheObservable.subscribe(/*your subscribe*/); } |
4 . composing multiple calls
5 . more robust interface than asyncTask
6 . easy to do complex threading
7 . functional nature is more expressive
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
/*一个数组,每个元素乘以2,然后筛选小于10的元素,放入集合中*/ Integer[] integers = { 0, 1, 2, 3, 4, 5 }; /*一般写法,看上去并不是那么的“函数”*/ Integer[] doubles = new Integer[integers.length]; for (int i = 0; i < integers.length; i++) { doubles[i] = integers[i] * 2; } List<Integer> integerList = new ArrayList<>(doubles.length); for (Integer integer : doubles) { if (integer < 10) integerList.add(integer); } /*Observable写法,一切都好多了*/ List<Integer> funactionalList = Observable.from(integers).map(new Func1<Integer, Integer>() { @Override public Integer call(Integer integer) {on-n">@Override public Integer call(Integer integer) {ming-with-Java-8-Tsvetinov-Nickolay/dp/1785288725/ref=sr_1_1?ie=UTF8&qid=1446964671&sr=8-1&keywords=Learning+Reactive+Programming+with+Java+8" target="_blank">《Learning Reactive Programming with Java 8》,《RxJava Essentials》,不过,没关系,我已经买到了电子版,我会在文章结尾附上网盘链接和密码,但我还是希望你将文章继续读下去,因为那是文章结尾的事。
其实关于RxJava的文章和消息远不止我们能了解到的,但又拜英语所赐,所以它看起来又没那么多。好在,国内有许多优秀的开发专家hi大头鬼hi ,BlackSwift,程序亦非猿,Drakeet,扔物线,流火枫林等等在为之做着贡献,以及简直不能更优秀的文章《给 Android 开发者的 RxJava 详解》。 但是,现在,我不得不再次做啰嗦一下,RxJava究竟会改变我们什么。 响应式编程Reactive Programming 什么是响应式编程呢?在Java程序中:
当我们改变“a”和“b”的值时,“c”并没有改变。换句话说,“a”和“b”的改变并没有响应到“c”。这就是响应式:程序以流的形式,传递数据的改变。 那我,我们又为什么需要响应式呢? 以下翻译自《Learning Reactive Programming with Java 8》
回调地狱 如果你是一个能够时刻保持头脑清醒,逻辑清晰和思维缜密的人,是个 那么在Android中你的代码可能会频繁的使用 那么关于异步回调的逻辑,你会写成这样 如果哪天你的程序出了问题而必须马上修复,但你却不能马上赶来或者需要别人协助(这在很多公司是很常见的),或者当他人在review你的代码时,那么,是时候拿出这张图了。 然而使用RxJava的操作符,我们可以避免这些烦人甚至糟糕的回调,让结构和思路看起来更清晰,通过组合API,只需要约定最终的结果 并且 当然RxJava的出现并不仅仅是为了解决回调地狱的。 这是我通过学习和不断地练习,一路走来很辛苦,总结的一些经验,分享给大家: 1 . error handling 3 . caching (roation)
4 . composing multiple calls 5 . more robust interface than asyncTask 6 . easy to do complex threading 7 . functional nature is more expressive
|