本系列的七篇文章(目前完成进度:2/7):
1、什么响应式编程
2、观察者模式及Rx基础概念解释
3、RxJava深入浅出
4、RxJava+Retrofit 的结合
5、RxJava的高阶使用
6、Retrofit的进阶应用
7、总结
观察者模式
其实非常简单,就是监听。我们在做Android开发的时候,必定绕不过的就是给Button设置监听器(你没做过算我输好吧):
bn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("TAG","OnCLick");
}
});
在上面的例子中,匿名内部类View.OnClickListener就是观察者,按钮bn就是被观察者。一旦被观察者被观察到“被点击”这个事件,观察者就会做出相应的反应(出log)。
是的,你已经用了很久的观察者模式了,只是你不知道而已。
观察者模式的描述应该是这样的:定义一个被观察对象,再定义一个(或多个)观察者,观察者时刻在观察着被观察对象的一举一动,一旦被观察对象的状态发生了变化,所有的观察者都会马上做出反应。
补充一点,在现实的编程中不会有“时刻都在观察”这种这么蠢的实现方式的,所以最好不要将观察者模式理解为'观察者'时刻监控着'被观察者'(虽然语义上这样的),应该理解为:'被观察者'其实是‘通知者’,自己有点什么状态变化(或者是什么事情发生)就马上通知"观察者"(就是实现约定好的),然后观察者再对此做出反应。(所以我个人更倾向于将“观察者模式”称为“通知者模式”)
回到本系列的第一篇,那个和全蛋一起工作的你。流水线模式是观察者模式吗,是吗?是的。但是,请注意,只有最后的打包员才是观察者!!!你们这些加工工人并不算是观察者,就算是观察者,地位也是比打包员的低的!(此处我是后来才意识到的,因而算是一个错误)
为什么这样说,其实大家可以理解为打包员才是可以睡懒觉的人,当然在加工工人没事做的时候也是在睡懒觉。但是,就算你们都是在睡懒觉,打包员才是“观察者”,当手机开始在流水线上流动的时候,流水线只会通知打包员,打包员一醒,就会把你们这些加工工人全部叫醒,帮他干活。(需要感受一下打包员和加工工人地位的差距,以及唤醒的时机)
现在再理一下思路:
- 流水线是“被观察者”,
- 流动着的手机是“数据流”,
- 打包员是“观察者”,
- 观察的事件是“手机毛坯进入流水线”,
- 观察者的响应动作是“将没有问题的手机打包好,有问题的手机另行处理”,
- 订阅是“事件发生以后响铃通知”。
- 至于加工工人,只是在观察者的响应动作发生前对数据流的处理。
(Ps,将“被观察者”换为“通知者”真的是会舒服很多)
用RxJava做个小Demo
例子还是我们的手机加工,废话不多说,直接上代码:
static void product() {
Phone[] phones = new Phone[5];
for (int i = 0; i < phones.length; i++) {
phones[i] = new Phone(i + "号iPhone");
}
Observable.from(phones) //Observable,被观察者
.map(new Func1<Phone, Phone>() { //装天线加工
@Override
public Phone call(Phone phone) {
try {
Thread.sleep(2000);
//为了体现顺序,我给加工设置了耗时
} catch (InterruptedException e) {
e.printStackTrace();
}
return phone.change("装了天线的");
}
})
.map(new Func1<Phone, Phone>() { //装摄像头加工
@Override
public Phone call(Phone phone) {
return phone.change("装了摄像头的、");
}
})
.subscribe(new Observer<Phone>() { //Observer,观察者订阅事件
@Override
public void onCompleted() {
System.out.println("搞掂,收工!");
}
@Override
public void onError(Throwable e) {
System.out.println("出了点小问题");
}
@Override
public void onNext(Phone phone) {
System.out.println(phone.show()+"被打包好了");
}
});
}
输出结果是:
装了摄像头的、装了天线的0号iPhone被打包好了
装了摄像头的、装了天线的1号iPhone被打包好了
装了摄像头的、装了天线的2号iPhone被打包好了
装了摄像头的、装了天线的3号iPhone被打包好了
装了摄像头的、装了天线的4号iPhone被打包好了
搞掂,收工!
Process finished with exit code 0
//附,这里的输出是每两秒输出一次
RxJava的基本概念
Observable:被观察者,也可解释为发射源,或数据流就是从这里发射出来的;
Observer:观察者,接收源,数据流就是在这里被接收;
Subscriber:“订阅者”,也是接收源,那它跟Observer有什么区别呢?Subscriber实现了Observer接口,比Observer多了一个最重要的方法unsubscribe( ),用来取消订阅,当你不再想接收数据了,可以调用unsubscribe( )方法停止接收,Observer 在 subscribe() 过程中,最终也会被转换成 Subscriber 对象,一般情况下,建议使用Subscriber作为接收源;
Subscription:Observable调用subscribe( )方法返回的对象,同样有unsubscribe( )方法,可以用来取消订阅事件;
Action0:RxJava中的一个接口,它只有一个无参call()方法,且无返回值,同样还有Action1,Action2...Action9等,Action1封装了含有 1 个参的call()方法,即call(T t),Action2封装了含有 2 个参数的call方法,即call(T1 t1,T2 t2),以此类推;
Func0:与Action0非常相似,也有call()方法,但是它是有返回值的,同样也有Func0、Func1...Func9;
关于Action 和 Func:
先说Func吧,在上面的demo中,我们用到了Func1,于是我们去看看Func1的源码:
/**
* Represents a function with one argument.
*/
public interface Func1<T, R> extends Function {
R call(T t);
}
非常短吧,只有一个方法call(T t),再跑去看看Func2的源码:
/**
* Represents a function with two arguments.
*/
public interface Func2<T1, T2, R> extends Function {
R call(T1 t1, T2 t2);
}
同样的,也是只有一个方法,call(T1 t1,T2 t2)。
再看回我们的Demo:
.map(new Func1<Phone, Phone>() { //装摄像头加工
@Override
public Phone call(Phone phone) {
return phone.change("装了摄像头的、");
}
})
在这里,我们想要做的是“给手机装摄像头”,我们的预期是我们提供一个方法给你,你只需要把“还没装摄像头的手机”当作是一个参数输入到这个方法里面,然后这个方法就会返回“装了摄像头的手机”。 (很明显,这段话的“你”指的是Rx框架)
然而,在Java中是没有方法指针这种东西,为了达到“将指定方法传递给Rx框架”的目的,设计者设计了Func和Action。
我们通过传递Func实例来传递一个方法!首先我们先新建一个Func1实例,然后将我们想要执行的方法写到Func1实例中的call方法中(覆盖),最后再把这个实例传递给Rx框架。Rx框架就会在指定的时刻执行我们Func1实例中的call方法,并把call方法的返回值传递到下一个流程。
大概就是这样了,通过传递实例来传递方法在Java中其实不少见,最常见的就是给Button传递一个OnClickListener来传递回调方法。
此外,我们在使用Func有时可能不止需要一个输入,可能要0个输入就好了,但有时需要可能需要2个、3个...输入的话,那该如何。
诸君莫方,我们还有Func0、Func1、Func2...肯定有一款适合你。Func后面的数字表示的是call方法的参数个数,我们只要根据需要选择Func接口就可以了(可看上面的两个Func接口的源码,比较出差别)。
说完Func,Action也就差不多了,Action和Func的区别就在于,Action没有返回值。
最后
似乎也没有什么好总结的了,就这样了吧。
Reference:http://www.jianshu.com/p/5e93c9101dc5
未经授权,禁止转载
原文地址:http://www.jianshu.com/p/b1bd50afb071