在Rxjava中Subject / Processor 是一种特殊的存在,它既是Observable又是Observer,
rxjava官网中给出的解释是可以将Subject / Processor看成是一个桥梁或者是代理.
Subject常见类型有:
AsyncSubject , BehaviorSubject , ReplaySubject, PublishSubject
Subject | 发射行为 |
AsyncSubject | 不论什么时候订阅只发射最后一个数据而且必须要调用onComplete()才会开始发射数据 |
BehaviorSubject | 发送订阅之前发射的最后一个数据(如果没有可以预定义一个默认的数据)和订阅之后的全部数据 |
ReplaySubject | 不论订阅发生在什么时候,都发射全部数据,可以自定义接收订阅之前的数据的数量和有效时间 |
PublishSubject | 发射订阅之后的全部数据 |
1.AsyncSubject
RxView.clicks(findViewById(R.id.btn_asyncsubject)).subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
//Subject中的AsyncSubject
//对于AsyncSubject 观察者Observer会接收AsyncSubject的onComplete()事件之前的最后一个数据
AsyncSubject<String> as = AsyncSubject.create();
as.onNext("as-----1 thread : " + Thread.currentThread().getName());
as.onNext("as-----2 thread : " + Thread.currentThread().getName());
as.onNext("as-----3 thread : " + Thread.currentThread().getName());
//注意:AsyncSubject必须要调用onComplete()才会开始发送数据否则观察者是不会接收到任何数据的
// as.onComplete();
as/*.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())*/
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG,"onSubscribe : " + d.isDisposed() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onNext(@NonNull String s) {
Log.d(TAG,"onNext : " + s + " thread : " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG,"onError : " + e.getMessage() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG,"onComplete : thread : " + Thread.currentThread().getName());
}
});
as.onNext("as--------4");
as.onNext("as---------5");
//改一下代码将onComplete()方法最后 我们发现放在中间时接收的是as---3事件
//而放在最后则是接收的是as-----5事件
as.onComplete();
}
});
打印结果:
2.BehaviorSubject
RxView.clicks(findViewById(R.id.btn_behaviorsubject)).subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
//Subject之BehaviorSubject
//BehaviorSubject的特性是会接收它被订阅(subscribe)之前的发射的最后一个数据以及还会接收被订阅(subscribe)之后发射的所有数据
//对于BehaviorSubject来说如果被订阅之前没有发射任何数据我们可以通过createDefault(T)方法设置一个默认
//数据那样即使在被订阅(subscribe)之前没有发射任何数据也会接收到这条默认的数据
// BehaviorSubject<Integer> bs = BehaviorSubject.create();
//创建BehaviorSubject时设置一个被订阅前如果没有发射数据时接收的默认数据
BehaviorSubject<Integer> bs = BehaviorSubject.createDefault(666);
bs.onNext(1);
bs.onNext(2);
bs.onNext(3);
bs.map(new Function<Integer, String>() {
@Override
public String apply(@NonNull Integer integer) throws Exception {
// Log.d(TAG,"map : thread " + Thread.currentThread().getName());
return String.valueOf(integer * 10);
}
}) .subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG,"onSubscribe : " + d.isDisposed() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onNext(@NonNull String s) {
Log.d(TAG,"onNext : " + s + " thread : " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG,"onError : " + e.getMessage() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG,"onComplete : thread : " + Thread.currentThread().getName());
}
});
bs.onNext(4);
bs.onNext(5);
//对于BehaviorSubject而言不管有没有调用onComplete()方法都会开始发送数据
// bs.onComplete();
bs.subscribe(new Consumer<Integer>() {
@Override
public void accept(@NonNull Integer s) throws Exception {
Log.d(TAG,"accept : " + s + " thread : " + Thread.currentThread().getName());
}
});
bs.onNext(6);
bs.onNext(7);
}
});
打印结果:
3.ReplaySubject
RxView.clicks(findViewById(R.id.btn_replaysubject)).subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
//Subject之ReplaySubject
//ReplaySubject会发射所有来自源Observable的数据给观察者,无论他们是什么时候订阅的
// ReplaySubject<Integer> rs = ReplaySubject.create();
//通过createWithSize可以指定缓存在订阅subscribe之前的几条数据 这个和BehaviorSubject有点像
// ReplaySubject<Integer> rs = ReplaySubject.createWithSize(2);
//也可以指定缓存数据的有效时间
// ReplaySubject<Integer> rs = ReplaySubject.createWithTime(10, TimeUnit.SECONDS, Schedulers.io());
//还可以指定缓存数据的数量和有效时间
ReplaySubject<Integer> rs = ReplaySubject.createWithTimeAndSize(10, TimeUnit.SECONDS, Schedulers.io(),2);
rs.onNext(1);
rs.onNext(2);
rs.onNext(3);
rs.map(new Function<Integer, String>() {
@Override
public String apply(@NonNull Integer integer) throws Exception {
return String.valueOf(integer * 10);
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG,"onSubscribe : " + d.isDisposed() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onNext(@NonNull String s) {
Log.d(TAG,"onNext : " + s + " thread : " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG,"onError : " + e.getMessage() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG,"onComplete : thread : " + Thread.currentThread().getName());
}
});
rs.onNext(4);
rs.onNext(5);
rs.onComplete();
}
});
打印结果:
4.PublishSubject
RxView.clicks(findViewById(R.id.btn_publishsubject)).subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
//Subject之PublishSubject
//PublishSubject的特点是它的订阅者Observer会接收它在被订阅之后发射的所有的数据
PublishSubject<Integer> ps = PublishSubject.create();
ps.onNext(1);
ps.onNext(2);
ps.onNext(3);
// ps.onComplete();
ps.map(new Function<Integer, String>() {
@Override
public String apply(@NonNull Integer integer) throws Exception {
return String.valueOf(integer * 2);
}
}).subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG,"onSubscribe : " + d.isDisposed() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onNext(@NonNull String s) {
Log.d(TAG,"onNext : " + s + " thread : " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG,"onError : " + e.getMessage() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG,"onComplete : thread : " + Thread.currentThread().getName());
}
});
ps.onNext(4);
ps.onNext(5);
ps.onComplete();
}
});
打印结果:
5.Subject的事件丢失问题
RxView.clicks(findViewById(R.id.btn_subjectmissdata)).subscribe(new Consumer<Object>() {
@Override
public void accept(@NonNull Object o) throws Exception {
//Subject错过事件的问题
PublishSubject<Integer> ps = PublishSubject.create();
ps.onNext(1);
ps.onNext(2);
ps.map(new Function<Integer, String>() {
@Override
public String apply(@NonNull Integer integer) throws Exception {
Log.d(TAG,"map : " + Thread.currentThread().getName());
return String.valueOf(integer);
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG,"onSubscribe : " + d.isDisposed() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onNext(@NonNull String s) {
Log.d(TAG,"onNext : " + s + " thread : " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG,"onError : " + e.getMessage() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG,"onComplete : thread : " + Thread.currentThread().getName());
}
});
ps.onNext(3);
ps.onNext(4);
for (int i = 0; i < 10000; i++) {
ps.onNext(i);
}
ps.onComplete();
//这种情况可以使用Observable.create()进行替代
/* Observable.create(new ObservableOnSubscribe<Integer>() {
@Override
public void subscribe(@NonNull ObservableEmitter<Integer> e) throws Exception {
for (int i = 0; i < 10000; i++) {
e.onNext(i);
}
e.onComplete();
}
}).map(new Function<Integer, String>() {
@Override
public String apply(@NonNull Integer integer) throws Exception {
return String.valueOf(integer);
}
}).subscribeOn(Schedulers.io())
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
Log.d(TAG,"onSubscribe : " + d.isDisposed() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onNext(@NonNull String s) {
Log.d(TAG,"onNext : " + s + " thread : " + Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
Log.d(TAG,"onError : " + e.getMessage() + " thread : " + Thread.currentThread().getName());
}
@Override
public void onComplete() {
Log.d(TAG,"onComplete : thread : " + Thread.currentThread().getName());
}
});
*/
}
});
打印结果:
将发射数据的线程切换到io线程 发射和订阅数据都在主线程
通过打印结果可以看出当我们通过subscribeOn()将PublishSubject发射数据的线程指定到了io线程以后会有一段时间订阅者
Observer没有接收到PublishSubject发射过来的数据导致数据丢失
这主要时因为当我们将发射数据的线程从主线程切换到io线程时io线程是需要进行初始化的,当我们在main主线程进行
数据的发送,而数据从主线程转发到io线程的过程中由于io线程在初始化
还没有起来就导致这部分数据被丢弃了所以就会看到有部分的数据没有打印出来
出现这种问题我们可以使用Observable来代替Subject进行操作,它允许为每个订阅者精确控制事件的发送