Grokking RxJava, Part 1: The Basics
来欣赏一下RxJava吧,第一部分:基础
RxJava是2014年这些日子里在Android开发者还是比较火的东西,它唯一的问题在于开始的时候比较难搞。万事开头难嘛..如果你一旦学会了,相当强大。
我尝试给你一个舒适一些的RxJava教程。我们的目标要四部曲入门RxJava。当然我不能解释一切啦,我只是想通过一个有趣的方式介绍RxJava是怎么工作的。
The Basics
基础模块 Observables(发射端) 和 Subscribers(消耗端)
这种模式的意义是Items是如何被emitt的,一个观察者也会发布许多Items(n多数量),然后当成功发送完成或者出现错误时候结束。
一个被订阅者(Observables)通过any number of times 调用Subscriber.onNext() 给每一个订阅的用户(Subscriber )发消息,然后调用Subscriber.onComplete() or Subscriber.onError().
他看起来有点像观察者模式,但是有一点不同的地方Observables ,通常不开始发送订阅数据直到有 明确的订阅用户订阅他们(这段可能有错
Observables often don’t start emitting items until someone explicitly subscribes to them2. don’t start .. until… )换句话说就是,如果没人监听广播,数据就不发,我们是伐木累!
Hello, World!
来来来,让我们看一下一个(凝固?)例子
First, let’s create a basic 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通过 sub.onNext() 发布 “Hello, world!” 然后调用 sub.onCompleted();
现在创建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发送的字符串。
现在我们获得myObservable 和mySubscriber,我们能通过subscribe()把他们联系起来。
myObservable.subscribe(mySubscriber);
// Outputs "Hello, world!"
当订阅创建成功,myObservable调用subscriber’s onNext() 和onComplete() 方法。因为这个结果mySubscriber 打印输出”Hello, world!”。
更简单的code
上面的代码只是发送”Hello,world!”,我通过一种啰嗦的方式展现了整个过程,让你看到每一步都发生了啥,当然可以简单很多,是RxJava编程更简单。
第一,简化 Observable 。RxJava 有多重内置构建啊…Observable 创造方法完成相同的工作。In this case,Observable.just()发送一个Item,然后completes,就像如下代码
Observable<String> myObservable =
Observable.just("Hello, world!");
Next,然我们处理一些不必要的Subscriber。
我们不必关心 onCompleted() nor onError(),因此替换我们用一个简单的类来定义我们要做的事情onNext():
Action1<String> onNextAction = new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
};
Actions可以定义每个Subscriber的一部分。
Observable.subscribe() 可以处理,一个,两个或者三个Action参数,来替换onNext(),onError()和onComplete()。复制我们的Subscriber 在上面的代码:
myObservable.subscribe(onNextAction, onErrorAction, onCompleteAction);
然而,我们只需要第一个参数,因为我们可以忽略onError() and onComplete():
myObservable.subscribe(onNextAction);
// Outputs "Hello, world!"
Now,让我们摆脱这些变量对方法调用的链接:
Observable.just("Hello, world!")
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
System.out.println(s);
}
});
最后如果你使用的java8 lambd的话,^◎^。
Observable.just("Hello, world!")
.subscribe(s -> System.out.println(s));
如果你使用Android(它不能用Java 8),我强烈建议使用retrolambd;
减少代码冗余。
Transformation
让我们增加情趣^_^。
假设我想添加我的签名“你好,世界!“输出。一种可能性的变化是Observable:
Observable.just("Hello, world! -Dan")
.subscribe(s -> System.out.println(s));
这个工作如果你想控制你的被订阅(Observable),但不能保证将会如此-如果你想用其他Library?其他潜在的问题,如果你想用Observable在跟复杂的地发而不是仅仅是一个签名,该怎么办呢?
我们试着修改用户(Subscriber )看看如何:
Observable.just("Hello, world!")
.subscribe(s -> System.out.println(s + " -Dan"));
这个答案也不令人满意,但是不同的原因:
我想我的Subscribers 尽可能变得轻量级,因为我需要运行他们在主线程。
在更高层次的概念上,Subscribers 应该是反应的东西,不是变化的东西。(完全翻译不通啊……..)
如果我改变发送”Hello,world!“的方式会不会很酷?
Introducing Operators
引入操作者
这是我们要如何解决项目迁移的问题:通过Operators,Operators可以用于source Observable的和the ultimate Subscriber之间的操作发出items。
RxJava自带了一个牛逼的收集的Operators,但首先最好关注一下,Operators是啥怎么回事。
由于这个情况,map() 这个 operator (操作符)可以用来改变一个?????(变换一个发布item到另外一个)
……对于这种情况,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));
此外,我们利用Lambdas简化代码
Observable.just("Hello, world!")
.map(s -> s + " -Dan")
.subscribe(s -> System.out.println(s));
相当酷巴,eh?我们的map() 关键字是基于Observable,map()是变换(transforms )一个项目。我们可以链接许多map()来实现我们想要做的事情,修正数据到完美,为我们的”end Subscriber”提供(消耗的格式?)consumable form 。
More on map()
map()这是一个有趣的方向:它没有发布相同类型的项目作为source Observable!
猜想一下我的Subscriber 并不是感兴趣输出的原始文本,但是反而想要输出hash of (散列?)文本
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接受一个Integer。Again,我们能使用lambdas 来简化代码:
Observable.just("Hello, world!")
.map(s -> s.hashCode())
.subscribe(i -> System.out.println(Integer.toString(i)));
像之前我说的那样,我们要我们的Subscriber 订阅者们去做的事情越少越好。让我们通过map()转换我们的hash back 到一个字符串。
Observable.just("Hello, world!")
.map(s -> s.hashCode())
.map(i -> Integer.toString(i))
.subscribe(s -> System.out.println(s));
Would you look at that - our Observable and Subscriber are back to their original code! We just added some transformational steps in between. We could even add my signature transformation back in as well:
Observable.just("Hello, world!")
.map(s -> s + " -Dan")
.map(s -> s.hashCode())
.map(i -> Integer.toString(i))
.subscribe(s -> System.out.println(s));
So What?