Subject是RxJava中的一个类,既可以作为观察者,也可以作为被观察者,可以用来做响应式编程。
Subject主要分为PublishSubject、ReplaySubject和BehaviorSubject三种,特性如下:
PublishSubject:广播Subject,向所有接收者发送事件,事件不存入缓存区
ReplaySubject:发送缓存区中最后几个事件,事件数量可以通过构造方法传进去
BehaviorSubject:发送缓存区中最后一个事件
下面,我通过一个例子,向大家演示三者的用法
在这个类里面,我们定义三个Subject和三个Observer,Observer用于监听事件的触发,然后把事件传递到Subject中,而后Subject再处理事件,完了在onSubscribe()中反馈结果。
1、定义ReactiveList类(单例,此处略过),使用泛型。在里面定义枚举类型,表示改变的类型(增删改)
public enum ChangeType {
ADD, REMOVE, UPDATE
}
2、定义一个LinkedList,做为数据源,一切改变由它而起;而后,定义三个Subject,分别表示改变种类(哪种改变)、改变的对象、最近改变的对象。Subject要指定两个泛型,前者是观察者类型,后者是被观察者类型,这里我们设置成一样的。
private LinkedList list = new LinkedList();
private Subject changes = null;//改变种类
private Subject changeValues = null;//改变的对象
private Subject latestChanged = null;//最近的改变对象
3、再定义三个Observer,用于监听事件的触发。
private Observer addObserver = null;
private Observer removeObserver = null;
private Observer updateObserver = null;
4、ReactList的构造方法,先初始化三个Subject:
changes = PublishSubject.create().toSerialized();
changeValues = ReplaySubject.createWithSize(5).toSerialized();
latestChanged = BehaviorSubject.create().toSerialized();
其中:toSerialized()方法用来保证线程安全
ReplaySubject的createWithSize()就是定义取出缓冲区最后多少个事件
5、紧接着,初始化三个Observer:
addObserver = new SerializedObserver<>(new Observer() {
@Override
public void onCompleted() {
changes.onCompleted();
changeValues.onCompleted();
}
@Override
public void onError(Throwable e) {
changes.onError(e);
changeValues.onError(e);
}
@Override
public void onNext(T t) {
add(t);
}
});
removeObserver = new SerializedObserver<>(new Observer() {
@Override
public void onCompleted() {
changes.onCompleted();
changeValues.onCompleted();
}
@Override
public void onError(Throwable e) {
changes.onError(e);
changeValues.onError(e);
}
@Override
public void onNext(T t) {
delete(t);
}
});
updateObserver = new SerializedObserver<>(new Observer() {
@Override
public void onCompleted() {
changes.onCompleted();
changeValues.onCompleted();
}
@Override
public void onError(Throwable e) {
changes.onError(e);
changeValues.onError(e);
}
@Override
public void onNext(T t) {
update(t);
}
});
其中为了线程安全,也使用了SerializedObserver,而在onNext()方法中,我是调用了自己封装的add、remove和update方法,它们仨的实现也很简单:
private void add(T value){
list.add(value);
changes.onNext(ChangeType.ADD);
changeValues.onNext(value);
latestChanged.onNext(value);
}
private void delete(T value){
if(list.contains(value)){
list.remove(value);
changes.onNext(ChangeType.REMOVE);
changeValues.onNext(value);
latestChanged.onNext(value);
}
}
private void update(T value){
if(list.contains(value)) {
int index = list.indexOf(value);
list.set(index,value);
changes.onNext(ChangeType.UPDATE);
changeValues.onNext(value);
latestChanged.onNext(value);
}
}
主要就是调用三个Subject的onNext()方法,此刻,Subject是做为被观察者
6、而后,向外界提供三个Subject和三个Observer的调用接口(六个get方法)
public Subject changes(){
return changes;
}
public Subject changesValues(){
return changeValues;
}
public Observable latestChanged(){
return latestChanged;
}
public Observer adder(){
return addObserver;
}
public Observer remover(){
return removeObserver;
}
public Observer updater(){
return updateObserver;
}
7、最后,给我们的list也写一个get方法,不过这个get方法,要返回一个被观察者
public Observable list(){
LinkedList copy = new LinkedList();
synchronized (copy){
copy.addAll(list);
}
return Observable.from(copy);
//创建操作符,创建一个被观察者,就自动发送事件
}
ReactList类构造完后,我们就可以在MainActivity中初始化数据了,写一个Student数组(Student就是java bean类,属性是id+name,无参+带参构造方法+get/set+toString())
private Student[] students = new Student[]{
new Student("001", "杰森伯恩"),
new Student("002", "托马斯穆勒"),
new Student("003", "莱万多夫斯基"),
new Student("004", "阿尔杰罗本"),
new Student("005", "弗兰克兰帕德"),
new Student("006", "史蒂文杰拉德"),
new Student("007", "诺伊尔"),
new Student("008", "罗伯特卡洛斯"),
new Student("009", "因扎吉"),
new Student("010", "里奥费迪南德")
};
根据前文我们知道,PublishSubject是向所有订阅者发送时间,不经过缓存区,而ReplaySubject和BehaviorSubject,它俩发送事件都是先放到缓存区里,所以我们在按顺序订阅Publish、Replay、Behavior的情况下,分三次实验:
第一次:在PublishSubject订阅之前,发送数据
第二次:在PublishSubject订阅之后,ReplaySubject订阅之前,发送数据
第三次:在三个Subject订阅之后,发送数据
我们把发送数据(按增、改、删顺序)统一封装成一个方法,名曰dataOperation():
private void dataOperation() {
for (int i = 0; i < students.length; i++) {
reactiveList.adder().onNext(students[i]);
}
reactiveList.list().subscribe(student -> Log.i(TAG, "list:" + student.toString()));
students[5].setName("卡尼吉亚");
reactiveList.updater().onNext(students[5]);
reactiveList.remover().onNext(students[0]);
}
而后,定义静态变量count,记录changeType的变化次数,进行三次实验:
/**
* 这种情况:先发事件,再订阅
* 对于Replay和Behavior,由于发事件的时候没有订阅者,事件全部进入缓存区。
* 而对于PublishSubject,它的事件由于不存入缓存区,所以都流失了。
* 最终结果:Replay和Behavior正常,Publish没有输出任何数据
*
* 此处,订阅者和subject就是观察者,我们(用户)、observer和subject则是被观察者,
* 因为我们调用了观察者observer的onNext()方法,observer调用了subject的onNext()方法,subject调用了订阅者的call()方法
*
* 所以这个案例的观察链就是:
* 用户->observer->subject->订阅者
*
*/
dataOperation();
reactiveList.changes().subscribe(changeType -> Log.i(TAG, "changeType-"+(++count)+":" + changeType));
reactiveList.changesValues().subscribe(student -> Log.i(TAG, "changesValues:" + student.toString()));
reactiveList.latestChanged().subscribe(student -> Log.i(TAG, "lastedChanged:" + student.toString()));
不多解释了,注释写的很清楚,我们看一下输出日志
可以看到,changeType(也就是Publish)的事件全部流失,而changesValues(Replay)和lastedChanged(Behavior)分别输出了最后五个事件(三个增加、一个更改,一个删除)和最后一个事件(删除)
reactiveList.changes().subscribe(changeType -> Log.i(TAG, "changeType-"+(++count)+":" + changeType));
/**
* 这种情况:先订阅Publish,再发数据,最后订阅Replay和Behavior:
* 由于发事件的时候,对于Replay和Behavior,情况和第一种一样,所以依旧正常
* 而对于Publish,由于是先订阅,所以数据发一次,订阅者就接收一次,故而正常输出
*/
dataOperation();
reactiveList.changesValues().subscribe(student -> Log.i(TAG, "changesValues:" + student.toString()));
reactiveList.latestChanged().subscribe(student -> Log.i(TAG, "lastedChanged:" + student.toString()));
而后,直接看日志
可以看到changeType(Publish)也正常输出了
reactiveList.changes().subscribe(changeType -> Log.i(TAG, "changeType-"+(++count)+":" + changeType));
reactiveList.changesValues().subscribe(student -> Log.i(TAG, "changesValues:" + student.toString()));
reactiveList.latestChanged().subscribe(student -> Log.i(TAG, "lastedChanged:" + student.toString()));
/**
* 这种情况:先订阅,再发事件
* 对于Replay,Behavior和Publish,由于发来一个事件就直接有订阅者接收,就不存在缓冲区的问题了
* 所以结果是发一次事件,三个都按接收顺序各输出一次
*/
dataOperation();
日志如下:
果然,是按着订阅顺序,发一次事件打印一次日志(包括lastedChanged(Behavior))。