响应式编程 android,Android中响应式编程--Subject的使用

Subject是RxJava中的一个类,既可以作为观察者,也可以作为被观察者,可以用来做响应式编程。

Subject主要分为PublishSubject、ReplaySubject和BehaviorSubject三种,特性如下:

PublishSubject:广播Subject,向所有接收者发送事件,事件不存入缓存区

ReplaySubject:发送缓存区中最后几个事件,事件数量可以通过构造方法传进去

BehaviorSubject:发送缓存区中最后一个事件

下面,我通过一个例子,向大家演示三者的用法

ReactiveList类

在这个类里面,我们定义三个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", "里奥费迪南德")

};

测试三个Subject的特性

根据前文我们知道,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()));

不多解释了,注释写的很清楚,我们看一下输出日志

7dff81b8ba0343a02019901900079510.png

可以看到,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()));

而后,直接看日志

d5a9d2904d9039fdc4840a8bbaed36db.png

可以看到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();

日志如下:

d5bfceda00c6769bd514e04193ad6759.png

果然,是按着订阅顺序,发一次事件打印一次日志(包括lastedChanged(Behavior))。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值