您的位置:首页 > 编程语言 > Java开发

了解RxJava之基础(一)

2016-03-29 17:06 357 查看
原文链接:Grokking RxJava, Part 1: The Basics

RxJava最近在Android开发者中火了起来。唯一的问题是入门比较困难,尤其是当你来自命令式编程的世界,但是一旦理解它,你就会发现RxJava真是太棒了。

这里仅仅是带你了解RxJava。整个系列共四篇文章,我希望你通过阅读之后对RxJava产生兴趣并了解RxJava的原理。

0x00 基础

响应式程序的核心是Observables和Subscribers。Observable发出一系列事件,Subscriber处理这些事件。

有对事件发射的模式。一个Observable可以发射任何事件(零个或者多个),直到结束或出错。对于每一个Subscriber,一个Observable调用Subscriber.onNext()任意次数,随后调用Subscriber.onComplete()Subscriber.onError()

这看起来很像标准的观察者模式,但它在一个关键的方法上有所不同。Observables往往不启动发射事件,直到有人显式的订阅这些事件。

0x01 Hello, World!

让我们以一个具体的例子来看看这个框架。首先,让我们创造一个基本的Observable:

Observable<String> myObservable = Observable.create(
new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> sub) {
sub.onNext("Hello, world!");
sub.onCompleted();
}
}
);


我们的Observable发射字符串”Hello, world!”,然后完成。现在让我们创建一个Subscriber消费这个数据:

Subscriber<String> mySubscriber = new Subscriber<String>() {
@Override
public void onNext(String s) { System.out.println(s); }

@Override
public void onCompleted() { }

@Override
public void onError(Throwable e) { }
};


这里仅仅是打印Observable发射的每个字符串。

现在我们通过subscribe()使myObservable和mySubscriber建立连接:

myObservable.subscribe(mySubscriber);
// Outputs "Hello, world!"


当订阅建立之后,myObservable调用mySubscriber的onNext和onComplete方法。mysubscriber输出“Hello, world!”,然后终止。

0x02 简化代码

这里有很多样板代码仅是要打印“Hello, world!”,这么啰嗦就是想让你了解发生了什么。RxJava提供了许多便捷方式以简化编程。

首先,让我们简化Observable创建,,RxJava对常见任务,有多个内置的操作符。在这种情况下,Observable.just()发射单个事件然后完成,就像上面的代码:

Observable<String> myObservable =
Observable.just("Hello, world!");


接下来,我们处理Subscriber中不需要的回调,在上面例子中我们只是让Observable发送一个数据,而且我们并没有覆写onComplete()和onError(),所以我们用一个简单的类定义在onNext()中做什么:

Action1<String> onNextAction = new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
};


Actions可以定义Subscriber的每一个动作,例如onNext(),onError,onComplete():

myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction);


然而,我们只需要第一个参数,因此先忽略onError()和onComplete():

myObservable.subscribe(onNextAction);
// Outputs "Hello, world!"


现在,让我们通过链式调用的方法摆脱那些变量:

Observable.just("Hello, world!")
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});


最后,让我们使用Java 8 的lambdas表达式避免这么丑陋的Action1代码:

Observable.just("Hello, world!")
.subscribe(s -> System.out.println(s));


如果你使用Android(因此不能使用Java 8),我强烈推荐你使用retrolambda,它能极大了减少冗长的代码。

0x03 变换

让我们做的更有趣些。

假设我想要在”Hello, world!”后追加签名,一种可能就是改变Observable,像这样:

Observable.just("Hello, world! -Dan")
.subscribe(s -> System.out.println(s));


这样只能在你的Observable是在你的控制之下,但不能保证总在这样的情况。假如你使用第三方库,一个潜在的问题:Observable在多处使用,但是只有一次需要附加签名,怎么做呢?

我们尝试修改我们的Subscriber,怎么样?

Observable.just("Hello, world!")
.subscribe(s -> System.out.println(s + " -Dan"));


这个答案也不尽人意,因为我想要Subscribers尽量的简单,Subscribers可能需要在主线程中运行。从概念层面,Subscribers应该是响应事件,而非修改事件。

那岂不是很酷,如果我可以在一些中间步骤改变“Hello, world!”?

0x04 使用变换操作符(Operators)

这里不是对RxJava所有Operators的介绍,如果需要更多的了解请移步这里

下面我要解决数据变换的问题,通过介于Observable与Subscriber之间的操作符。RxJava带有大量的操作符集合,但我们目前最好只关注极少数。

对于这种情况,map()操作符可以用于变换被发射的数据:

Observable.just("Hello, world!")
.map(new Func1<String, String>() {
@Override
public String call(String s) {
return s + " -Dan";
}
})
.subscribe(s -> System.out.println(s));


我们再次通过lambda表达式简化:

Observable.just("Hello, world!")
.map(s -> s + " -Dan")
.subscribe(s -> System.out.println(s));


很酷,不是吗?我们的map()操作符变换发射的数据并返回另外的Observable,我们可以链式调用map(),变换数据到Subscriber最终消费形式。

0x05 map()操作符(Operators)

map操作符有个有趣的方面,它不必返回与源Observable相同的返回类型

假定我的Subscriber对输出原文本不感兴趣,而是要输出文本的哈希值:

Observable.just("Hello, world!")
.map(new Func1<String, Integer>() {
@Override
public Integer call(String s) {
return s.hashCode();
}
})
.subscribe(i -> System.out.println(Integer.toString(i)));


有趣,我们开始用一个字符串,但最终我们的Subscriber收到一个整数,我们再次用lambda表达式简化这段代码:

Observable.just("Hello, world!")
.map(s -> s.hashCode())
.subscribe(i -> System.out.println(Integer.toString(i)));


如我之前所说,我们希望我们的Subscriber尽可能做的更少,我们用另一个map把字符串哈希转会字符串:

Observable.just("Hello, world!")
.map(s -> s.hashCode())
.map(i -> Integer.toString(i))
.subscribe(s -> System.out.println(s));


请看:我们的Observable和Subscriber都回到了他们原来的代码,我们只是增加了一些转换步骤。我们同样可以添加我的签名然后变换:

Observable.just("Hello, world!")
.map(s -> s + " -Dan")
.map(s -> s.hashCode())
.map(i -> Integer.toString(i))
.subscribe(s -> System.out.println(s));


0x06 那又怎样?

在这一点上,你可能认为,这些是简单的代码加入了很多花式。这时一个简单的例子,但是你应该从中获得两种理念:

1.Observable和Subscriber可以做任何事情

Observable发射的事件可以来自是一个数据库查询,Subscriber用来显示查询结果;也可以来自屏幕上的点击事件,Subscriber用来响应点击事件;Observable可以是一个网络请求返回的数据流,Subscriber用来向硬盘写入结果。

这是一个可以处理任何问题的通用框架。

2.Observable和Subscriber是独立于中间的变换过程的

在Observable和Subscriber中间可以链式调用很多map操作符,该系统具有高度的可组合性:它很容易操纵数据。只要操作符数据输入输出都正确,就可以一直链式调用下去。

结合以上两个主要的想法,你可以看到一个具有很大的潜力的系统,虽然当前我们只知道map操作符,这严重限制了我们的能力。在第2部分,我们将畅游RxJava提供的大量操作符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: