Rxjava 的原理
- Observable:发射源,可观察的,在官擦着模式中被称为”被观察者
- Observer:接收源,观察者,可接受Observable,subject发送的数据
- Subject:即可当接受者,也可以当被观察者
- Subscriber: 订阅者,接收源,实现了Observer接口,比Observer多了一个接口unSubscribe取消订阅,建议使用Subscriber接收源.
- Subscription: Observable 调用subscribe() 方法返回的对象,同样有unsbscribe()方法,可以用来取消订阅事件.
- Action0: Rxjava 中的一个接口,他只有一个无参call()方法,且无返回值,同样还有Action1(),Action2(),,,封装了一个参数,两个参数,一直到9个参数的
- Fun0(): 于Action0相同,只是这个有返回值的,相同的也是从0-9 依次带参数;
Observable的使用
- 使用create创建(基本不用)
Observable normalObservable = Observable.create(new Observable.OnSubscribe<String>() {
@Overridepublic void call(Subscriber<? super String> subscriber) {
subscriber.onNext("create1"); //发射一个"create1"的String
subscriber.onNext("create2"); //发射一个"create2"的String
subscriber.onCompleted();//发射完成,这种方法需要手动调用onCompleted,才会回调Observer的onCompleted方法
}});
- 使用 just() 将为你创建一个Observable并自动为你调用onNext( )发射数据
justObservable = Observable.just("just1","just2");//依次发送"just1"和"just2"
- 使用from遍历集合,依次发送每个item
List<String> list = new ArrayList<>();
list.add("from1");
list.add("from2");
list.add("from3");
fromObservable = Observable.from(list); //遍历list 每次发送一个
/** 注意,just()方法也可以传list,但是发送的是整个list对象,而from()发送的是list的一个item** /
- 使用defer() 有观察者的时候才创建被观察者,并且每次都创建一个新的Obsevable对象
deferObservable = Observable.defer(new Func0<Observable<String>>() {
@Override
//注意此处的call方法没有Subscriber参数public Observable<String> call() {
return Observable.just("deferObservable");
}});
- 使用interval() 设置每隔多长时间请求一次,通常用于计时器,从1忘上数的即时,如果想要倒数,注意线程的切换,使用map从60-i,即可
intervalObservable = Observable.interval(1, TimeUnit.SECONDS);//每隔一秒发送一次
//interval()是运行在computation Scheduler线程中的,因此需要转到主线程
mSubscription=Observable
.interval(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.map(new Func1<Long, Long>() { //使用map将数据转化
@Override
public Long call(Long aLong) {
return 60 - aLong;
}
})
.subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
mText.setText(aLong+"S");
}
});
- 使用range()创建一个发送特定整数数列的Observable,第一个参数为起始值,第二个参数为发送的长度,如果为0不发送,如果为负抛出异常;
rangeObservable = Observable.range(10, 5);//将发送整数10,11,12,13,14
- 使用timer(),创建一个Observable,给定一个延迟后发射一条数据,等同于Android中的Handler的postDely()方法,注意线程的切换,这个是运行咋子线程的
timeObservable = Observable.timer(3, TimeUnit.SECONDS); //3秒后发射一个值
- 使用repeat()创建一个重复发送特定数据的ObserVable
repeatObservable = Observable.just("repeatObservable").repeat(3);//重复发射3次
Observer的创建
1.普通接受,基本不用
mObserver = new Observer<String>() {
@Overridepublic void onCompleted() {
LogUtil.log("onCompleted"); // 全部打印时候调用
}
@Overridepublic void onError(Throwable e) {
}
@Overridepublic void onNext(String s) {
LogUtil.log(s); // 依次打印数据先OnNext的先打印
}};
- 可以使用subscribe中的Action1接受传入
Subscribe的源码
//一个参数的Action
public final Subscription subscribe(final Action1<? super T> onNext)
//带有错误的参数
public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError)
//带有完成的参数
public final Subscription subscribe(final Action1<? super T> onNext, final Action1<Throwable> onError, final Action0 onCompleted)
//示例
Observable.just(1,2,3,4).subscribe(new Action1<Long>() {
@Override
public void call(Long aLong) {
mText.setText(aLong + "S");
}
},
new Action1<Throwable>() {
@Override
public void call(Throwable e) {
//错误的方法
e.printStackTrace();
}
}, new Action0() {
@Override
public void call() {
//这个是全部完成的方法
System.out.println("我是全部完成的");
}
}
);
Subject
定义
- Subject可以看成是一个桥梁或者代理,在某些ReactiveX实现中(如RxJava),它同时充当了Observer和Observable的角色。因为它是一个Observer,它可以订阅一个或多个Observable;又因为它是一个Observable,它可以转发它收到(Observe)的数据,也可以发射新的数据.
- 它可以充当Observable;
- 它可以充当Observer;
- 它是Observable和Observer之间的桥梁;
Subject是一个抽象类,不能通过new来实例化Subject,所以Subject有四个实现类,分别为AsyncSubject、BehaviorSubject、PublishSubject和ReplaySubject,每个实现类都有特定的“技能”,下面结合代码来介绍一下它们各自的“技能”。注意,所有的实现类都由create()方法实例化,无需new,所有的实现类调用onCompleted()或onError(),它的Observer将不再接收数据;
AsyncSubject:Observer会接收AsyncSubject的`onComplete()之前的最后一个数据,如果因异常而终止,AsyncSubject将不会释放任何数据,但是会向Observer传递一个异常通知.
//只会接受onCompleted之前的第一个onNext的值;如果不调用onCompleted(),Subscriber将不接收任何数据。
AsyncSubject<String> strAsyncSubject = AsyncSubject.create();
strAsyncSubject.onNext("我");
strAsyncSubject.onNext("爱");
strAsyncSubject.onNext("你");
strAsyncSubject.onCompleted();
strAsyncSubject.subscribe(new Action1<String>() {
@Override
public void call(String s) {
// System.out: 你
System.out.println(s);
}
});
- BehaviorSubject:
Observer会接收到BehaviorSubject被订阅之前的最后一个数据,再接收其他发射过来的数据,如果BehaviorSubject被订阅之前没有发送任何数据,则会发送一个默认数据。(注意跟AsyncSubject的区别,AsyncSubject要手动调用onCompleted(),且它的Observer会接收到onCompleted()前发送的最后一个数据,之后不会再接收数据,而BehaviorSubject不需手动调用onCompleted(),它的Observer接收的是BehaviorSubject被订阅前发送的最后一个数据,两个的分界点不一样,且之后还会继续接收数据。)示例代码如下:
BehaviorSubject<String> strBehaviorSubject = BehaviorSubject.create("梦");
strBehaviorSubject.onNext("我");
strBehaviorSubject.onNext("爱");
//此时被订阅会找到上一个onNext的值:爱, 如果没有onNext会发送一个默认值create里面的:梦
strBehaviorSubject.subscribe(new Action1<String>() {
@Override
public void call(String s) {
///System.out: 爱
//System.out: 你
System.out.println(s);
}
});
strBehaviorSubject.onNext("你");
- PublishSubject: 它的Observer只会接收到PublishSubject被订阅之后发送的数据。
PublishSubject<String> strPublishSubject = PublishSubject.create();
strPublishSubject.onNext("我");
strPublishSubject.onNext("爱");
strPublishSubject.subscribe(new Action1<String>() {
@Override
public void call(String s) {
//System.out: 你
//System.out: !
System.out.println(s);
}
});
strPublishSubject.onNext("你");
strPublishSubject.onNext("!");
- ReplaySubject
ReplaySubject会发射所有数据给观察者,无论它们是何时订阅的。也有其它版本的ReplaySubject,在重放缓存增长到一定大小的时候或过了一段时间后会丢弃旧的数据。
//创建默认初始缓存容量大小为16的ReplaySubject,当数据条目超过16会重新分配内存空间,使用这种方式,不论ReplaySubject何时被订阅,Observer都能接收到数据
ReplaySubject<String> replaySubject = ReplaySubject.create();
// 创建指定初始缓存容量大小为100的ReplaySubject
//replaySubject = ReplaySubject.create(100);
// 只缓存订阅前最后发送的2条数据
//replaySubject = ReplaySubject.createWithSize(2);
// replaySubject被订阅前的前1秒内发送的数据才能被接收
//replaySubject=ReplaySubject.createWithTime(1,TimeUnit.SECONDS,Schedulers.computation());
replaySubject.onNext("replaySubject:pre1");
replaySubject.onNext("replaySubject:pre2");
replaySubject.onNext("replaySubject:pre3");
replaySubject.subscribe(new Action1<String>() {
@Override
public void call(String s) {
//由上到下依次打印数据
System.out.println(s);
}
});
replaySubject.onNext("replaySubject:after1");
replaySubject.onNext("replaySubject:after2");
- SerializedSubject
Subject 当作一个 Subscriber 使用,不要从多个线程中调用它的onNext方法(包括其它的on系列方法),这可能导致同时(非顺序)调用,这会违反Observable协议,给Subject的结果增加了不确定性。要避免此类问题,官方提出了“串行化”,你可以将 Subject 转换为一个 SerializedSubject
SerializedSubject<String, Integer> ser = new SerializedSubject(publishSubject);
- subject:Subject继承了Observable,又实现了Observer接口,所以说它既是Observable又是Observer,所以Subject也能实现Observable和Observer相同的功能
public abstract class Subject<T, R> extends Observable<R> implements Observer<T>
//使用subject实现订阅跟发送
PublishSubject<String> publishSubject = PublishSubject.create();
Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> subscriber) {
subscriber.onNext("as Bridge");
subscriber.onNext("as Bridge");
subscriber.onNext("as Bridge");
subscriber.onCompleted();
}
}).subscribe(publishSubject);
publishSubject.subscribe(new Observer<String>() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
System.out.println("我是错误的");
e.printStackTrace();
}
@Override
public void onNext(String s) {
System.out.println("woshi" + s);
}
});
Scheduler:调度器
注意SubscribeOn只能调取一次,以第一次为准,并使其上的代码运行在其指定的线程内,下面如果再次调用将没有效果,ObserveOn其下面的代码运行在其指定的线程内,注意一些耗时操作的操作符需要更改线程,切记切记切记,重要的事情讲三遍
思考:我们经常多次使用subscribeOn切换线程,那么以后是否可以组合observeOn和subscribeOn达到自由切换的目的呢?
组合是可以的,但是他们的执行顺序是有条件的,如果仔细分析的话,可以知道observeOn调用之后,再调用subscribeOn是无效的,原因是什么?
因为subscribeOn改变的是subscribe这句调用所在的线程,大多数情况,产生内容和消费内容是在同一线程的,所以改变了产生内容所在的线程,就改变了消费内容所在的线程。
经过上面的阐述,我们知道,observeOn的工作原理是把消费结果先缓存,再切换到新线程上让原始消费者消费,它和生产者是没有一点关系的,就算subscribeOn调用了,也只是改变observeOn这个消费者所在的线程,和OperatorObserveOn中存储的原始消费者一点关系都没有,它还是由observeOn控制。
下面提到的“操作”包括产生事件、用操作符操作事件以及最终的通过 subscriber 消费事件;
- 只有第一subscribeOn() 起作用(所以多个 subscribeOn() 无意义);
- 这个 subscribeOn() 控制从流程开始的第一个操作,直到遇到第一个 observeOn();
- observeOn() 可以使用多次,每个 observeOn() 将导致一次线程切换(),这次切换开始于这次 observeOn() 的下一个操作;
- 不论是 subscribeOn() 还是 observeOn(),每次线程切换如果不受到下一个 observeOn() 的干预,线程将不再改变,不会自动切换到其他线程。
常用的操作符
*Map:最常用且最实用的操作符之一,将对象转换成另一个对象发射出去,应用范围非常广,如数据的转换,数据的预处理等
Observable.just("12345678").map(new Func1<String, String>() {
@Override
public String call(String s) {
return s.substring(0,4);//只要前四位
}})
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
Log.i("mytag",s);
}});
- FlatMap:和Map很像但又有所区别,Map只是转换发射的数据类型,而FlatMap可以将原始Observable转换成另一个Observable。
Observable.from(schoolList).flatMap(new Func1<School, Observable<School.Student>>() {
@Override
public Observable<School.Student> call(School school) {
return Observable.from(school.getStudentList()); //关键,将学生列表以另外一个Observable发射出去
}}).subscribe(new Action1<School.Student>() {
@Override
public void call(School.Student student) {
Log.i("mytag",student.getName());
}});
- Buffer :缓存,可以设置缓存大小,缓存满了,以List方式将数据发送,通常跟Map一起使用:注意线程的调度
List<School> schoolList = new ArrayList<>();
Observable.from(schoolList).map(new Func1<School, School>() {
@Overridepublic School call(School school) {
school.setName("NB大学"); //将所有学校改名return school;
}}).buffer(schoolList.size()) //缓存起来,最后一起发送
.subscribe(new Action1<List<School>>() {
@Overridepublic void call(List<School> schools) {
}});
- Take:发送前n项数据
Observable.from(schoolList).take(4).map(new Func1<School, School>() {
@Override
public School call(School school) {
school.setName("NB大学");
return school;
}}).buffer(4).subscribe(new Action1<List<School>>() {
@Override
public void call(List<School> schools) {
}});
- Distinct:去掉重复的项
Observable.just(1, 2, 1, 1, 2, 3)
.distinct()
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer item) {
System.out.println("Next: " + item);
}
});
- Filter: 过滤
Observable.just(1, 2, 3, 4, 5)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer item) {
return( item < 4 );
}
}).subscribe(new Action1<Integer>() {
@Override
public void call(Integer item) {
System.out.println("Next: " + item);
}});
- marge两个任务并发进行,全部处理完毕之后在更新数据
Observable obs1=Observable.create(new Observable.OnSubscribe<String>(){
@Override
public void call(Subscriber<? super String> subscriber) {
try {
Thread.sleep(500);
subscriber.onNext(" aaa");
subscriber.onCompleted();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).subscribeOn(Schedulers.newThread());
Observable obs2=Observable.create(new Observable.OnSubscribe<String>(){
@Override
public void call(Subscriber<? super String> subscriber) {
try {
Thread.sleep(1500);
subscriber.onNext("bbb");
subscriber.onCompleted();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).subscribeOn(Schedulers.newThread());
Observable.merge(obs1,obs2)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<String>() {
StringBuffer sb=new StringBuffer();
@Override
public void onCompleted() {
mText.append("两个任务都处理完毕!!\n");
mText.append("更新数据:"+sb+"\n");
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(String s) {
sb.append( s+",");
mText.append("得到一个数据:"+s+"\n");
}
});
- RxBinding跟Rxjava相结合
RxTextView.textChanges(mEdit)
//在一次事件发生后的一段时间内没有新操作,则发出这次事件
.debounce(500,TimeUnit.MILLISECONDS)
//转换线程
.observeOn(Schedulers.newThread())
//通过输入的数据,来匹配"数据库"中的数据从而提示。。
.map(new Func1<CharSequence, List<String>>() {
List<String> list=new ArrayList<String>();
@Override
public List<String> call(CharSequence charSequence) {
if (charSequence.toString().contains("1")){
for (int i=0;i<5;i++){
list.add("11"+i);
}
}
return list;
}
})
//由于我不想要listl列表,所以使用了flatMap来分解成一个一个的数据发送
.flatMap(new Func1<List<String>, Observable<String>>() {
@Override
public Observable<String> call(List<String> strings) {
return Observable.from(strings);
}
})
//这里切换成主线程,不然没法操作组件
.observeOn(AndroidSchedulers.mainThread())
//这里做一些过滤动作
.filter(new Func1<String, Boolean>() {
@Override
public Boolean call(String s) {
return !mText.getText().toString().contains(s);
}
})
//订阅
.subscribe(new Action1<String>() {
@Override
public void call(String s) {
//这里展示提示数据
mText.append(s + "\n");
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable throwable) {
Log.w("DDDDDDDD",throwable.getMessage().toString());
}
});
mBtn.setText("连续点击防误触");
RxView.clicks(mBtn)
//防误触(设定点击后500ms内丢弃新事件,或者说点击后500ms毫秒无响应)
.throttleFirst(500, TimeUnit.MILLISECONDS)
.subscribe(new Action1<Void>() {
//这就相当于OnClickListener中的OnClick方法回调
@Override
public void call(Void aVoid) {
mText.append("\n 防误触 测试 \n");
}
});
*doOnNext:每次观察者中的onNext调用之前调用
// Integer [] number={1,2,3,4,5,6,7,8,9,10};
Observable.from(number)
.filter(new Func1<Integer, Boolean>() {
@Override
public Boolean call(Integer integer) {
return integer%2!=0;
}
})
//取前四个
.take(4)
//取前四个中的后两个
.takeLast(2)
.doOnNext(new Action1<Integer>() { //每个onNext之前调用
@Override
public void call(Integer integer) {
mText.append("before onNext()\n");
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer integer) {
mText.append("onNext()--->"+integer+"\n");
}
});
//system:before onNext()
//onNext()--->5
//system:before onNext()
//onNext()--->7
*toSortedList() :为事件中的数据排序
Integer [] words={1,3,5,2,34,7,5,86,23,43};
Observable.from(words)
.toSortedList()
.flatMap(new Func1<List<Integer>, Observable<Integer>>() {
@Override
public Observable<Integer> call(List<Integer> strings) {
return Observable.from(strings);
}
})
.subscribe(new Action1<Integer>() {
@Override
public void call(Integer strings) {
mText.append(strings+"\n");
}
});
- connect模式: Observable发送事件1-6,两个观察者同时观察这个Observable \n要求:每发出一个事件,观察者A和观察者都会收到,而不是先把所有的时间发送A,然后再发送给B
// Integer [] integer={1,2,3,4,5,6};
//正常模式 A先接受完数组在给B接受
Observable observable= Observable.from(integer);
Action1 a1=new Action1<Integer>(){
@Override
public void call(Integer o) {
mText.append("观察者A 收到: "+o+"\n");
}
};
Action1 a2=new Action1<Integer>(){
@Override
public void call(Integer o) {
mText.append("观察者B 收到: "+o+"\n");
}
};
observable.subscribe(a1);
observable.subscribe(a2);
//connect模式下A跟B一起收模式为1,1,2,2,3,3...就是A,B,A,B...
ConnectableObservable observable= Observable.from(integer)
.publish();//将一个Observable转换为一个可连接的Observable
Action1 a1=new Action1<Integer>(){
@Override
public void call(Integer o) {
mText.append("观察者A 收到: "+o+"\n");
}
};
Action1 a2=new Action1<Integer>(){
@Override
public void call(Integer o) {
mText.append("观察者B 收到: "+o+"\n");
}
};
observable.subscribe(a1);
observable.subscribe(a2);
observable.connect();
- timestamp() :为每个事件加上一个时间戳
Integer [] words={1,3,5,2,34,7,5,86,23,43};
Observable.from(words)
.timestamp()
// .timestamp(Schedulers.io()) 可指定线程环境,如果指定到子线程,请在最后切换成主线程
.subscribe(new Action1<Timestamped<Integer>>() {
@Override
public void call(Timestamped<Integer> integerTimestamped) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd-HH:mm:ss");
mText.append("value: "+integerTimestamped.getValue()+" time: ");
mText.append(sdf.format(new Date(integerTimestamped.getTimestampMillis()))+"\n");
}
});