本文篇幅较长 建议收藏起来等时间空闲详细阅读
本篇文章主要是一份学习笔记
文章目录
RXJava入门教程
定义
RxJava是一个在java VM上可以使用可观测的序列来组成异步的,基于事件的程序库, RxJava是一个基于时间流.实现异步操作的库
作用
实现异步 类似于android中的ASyncTask,Handler作用
特点
基于事件流的链式调用,保持代码简洁&优雅
原理分析
生活场景: 去吃饭.
- RxJava原理是基于一种扩展的观察者模式
- RxJava的扩展观察者模式4个角色
角色 | 作用 | 类比 |
---|---|---|
被观察者Observable | 产生事件 | 顾客 |
观察者Observer | 接受事件,并作出相应动作 | 厨房 |
订阅者Subscribe | 连接被观察者&观察者 | 服务员 |
事件Event | 被观察者*观察者 沟通的载体 | 菜式 |
原理总结为被观察者通过订阅者按顺序发送事件给观察者,观察者按事件接受事件的顺序&做出对应的响应动作.
分步骤实现
-
创建被观察者(Observable)并且产生事件
-
即顾客到饭店–>坐到位置–>点菜 具体实现;
// 1. 创建被观察者 Observable 对象 Observable<Integer> observable = Observable.create(new ObservableOnSubscribe<Integer>() { // create() 是 RxJava 最基本的创造事件序列的方法 // 此处传入了一个 OnSubscribe 对象参数 // 当 Observable 被订阅时,OnSubscribe 的 call() 方法会自动被调用,即事件序列就会依照设定依次被触发 // 即观察者会依次调用对应事件的复写方法从而响应事件 // 从而实现被观察者调用了观察者的回调方法 & 由被观察者向观察者的事件传递,即观察者模式 // 2. 在复写的subscribe()里定义需要发送的事件 @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { // 通过 ObservableEmitter类对象产生事件并通知观察者 // ObservableEmitter类介绍 // a. 定义:事件发射器 // b. 作用:定义需要发送的事件 & 向观察者发送事件 emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); emitter.onComplete(); } }); <--扩展:RxJava 提供了其他方法用于 创建被观察者对象Observable --> // 方法1:just(T...):直接将传入的参数依次发送出来 Observable observable = Observable.just("A", "B", "C"); // 将会依次调用: // onNext("A"); // onNext("B"); // onNext("C"); // onCompleted(); // 方法2:from(T[]) / from(Iterable<? extends T>) : 将传入的数组 / Iterable 拆分成具体对象后,依次发送出来 String[] words = {"A", "B", "C"}; Observable observable = Observable.from(words); // 将会依次调用: // onNext("A"); // onNext("B"); // onNext("C"); // onCompleted();
-
-
创建观察者(Observer)并且定义响应事件行为
发生的事件类型包括 Next事件,complete事件,error事件
事件类型 定义 作用 使用规则 使用方法 Next 普通时间 向观察者发送需要响应事件的信号 被观察者可无限次的发送Next事件,观察者无限次接受事件 onNext Complete 事件队列完结,(事件) 标志,被观察者,不在发送普通事件 1. 当被观察者发送了一个Complete事件后被观察者在complete事件后的事件将会继续发送,但是观察者收到complete事件后将不会再接受任何事件
2.被观察者可以不发送complete事件onCompleted() error 事件队列异常 (事件) 标志 事件处理过程中出现异常 1. 当被观察者发送一个Error事件后,被观察者在error事件后的事件将会继续发送,但是观察者收到error事件后将不会继续接受任何事件
2.被观察者可以不发送Error事件onErrror() 在一个正确运行的事件序列中:onComplete和onError事件相互排斥,只能拥有唯一的一个事件.
具体实现:
<--方式1:采用Observer 接口 --> // 1. 创建观察者 (Observer )对象 Observer<Integer> observer = new Observer<Integer>() { // 2. 创建对象时通过对应复写对应事件方法 从而 响应对应事件 // 观察者接收事件前,默认最先调用复写 onSubscribe() @Override public void onSubscribe(Disposable d) { Log.d(TAG, "开始采用subscribe连接"); } // 当被观察者生产Next事件 & 观察者接收到时,会调用该复写方法 进行响应 @Override public void onNext(Integer value) { Log.d(TAG, "对Next事件作出响应" + value); } // 当被观察者生产Error事件& 观察者接收到时,会调用该复写方法 进行响应 @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } // 当被观察者生产Complete事件& 观察者接收到时,会调用该复写方法 进行响应 @Override public void onComplete() { Log.d(TAG, "对Complete事件作出响应"); } }; <--方式2:采用Subscriber 抽象类 --> // 说明:Subscriber类 = RxJava 内置的一个实现了 Observer 的抽象类,对 Observer 接口进行了扩展 // 1. 创建观察者 (Observer )对象 Subscriber<String> subscriber = new Subscriber<Integer>() { // 2. 创建对象时通过对应复写对应事件方法 从而 响应对应事件 // 观察者接收事件前,默认最先调用复写 onSubscribe() @Override public void onSubscribe(Subscription s) { Log.d(TAG, "开始采用subscribe连接"); } // 当被观察者生产Next事件 & 观察者接收到时,会调用该复写方法 进行响应 @Override public void onNext(Integer value) { Log.d(TAG, "对Next事件作出响应" + value); } // 当被观察者生产Error事件& 观察者接收到时,会调用该复写方法 进行响应 @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } // 当被观察者生产Complete事件& 观察者接收到时,会调用该复写方法 进行响应 @Override public void onComplete() { Log.d(TAG, "对Complete事件作出响应"); } }; <--特别注意:2种方法的区别,即Subscriber 抽象类与Observer 接口的区别 --> // 相同点:二者基本使用方式完全一致(实质上,在RxJava的 subscribe 过程中,Observer总是会先被转换成Subscriber再使用) // 不同点:Subscriber抽象类对 Observer 接口进行了扩展,新增了两个方法: // 1. onStart():在还未响应事件前调用,用于做一些初始化工作 // 2. unsubscribe():用于取消订阅。在该方法被调用后,观察者将不再接收 & 响应事件 // 调用该方法前,先使用 isUnsubscribed() 判断状态,确定被观察者Observable是否还持有观察者Subscriber的引用,如果引用不能及时释放,就会出现内存泄露
-
通过订阅者(subscribe)连接被观察者和观察者
即顾客点菜–>服务员下单到厨房–>厨房做菜
具体实现
observable.subscribe(observer) //扩展说明 <-- Observable.subscribe(Subscriber) 的内部实现 --> public Subscription subscribe(Subscriber subscriber) { subscriber.onStart(); // 步骤1中 观察者 subscriber抽象类复写的方法,用于初始化工作 onSubscribe.call(subscriber); // 通过该调用,从而回调观察者中的对应方法从而响应被观察者生产的事件 // 从而实现被观察者调用了观察者的回调方法 & 由被观察者向观察者的事件传递,即观察者模式 // 同时也看出:Observable只是生产事件,真正的发送事件是在它被订阅的时候,即当 subscribe() 方法执行时.
RxJava操作符
基本操作
-
create()
作用: 完整创建一个被观察者(Observable),最基本的操作符
具体使用:
Observable.create(new ObservableOnSubscribe<Integer>() { @Override public void subscribe(ObservableEmitter<Integer> emitter) throws Exception { emitter.onNext(1); emitter.onNext(3); emitter.onNext(4); emitter.onComplete(); } }).subscribe(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { Log.e(TAG, "onSubscribe"); } @Override public void onNext(Integer integer) { Log.e(TAG, "integer" + integer); } @Override public void onError(Throwable e) { Log.e(TAG, "onError"); } @Override public void onComplete() { Log.e(TAG, "onComplete"); } }); //依次执行 onSubscribe-->integer1-->integer2-->integer3-->onComplete 如果那个步骤出错会执行onError
-
快速创建&&发送事件
-
just()
快速创建被观察者对象(observable),直接传入发送的事件,最多可发送10个事件
-
fromArray()
快速创建被观察者对象(observable),直接传入数组发送事件,只能传入数组,传入list默认为一个事件
-
fromltearable()
快速创建被观察对象(observable) 直接传入集合对象,
-
never()
不发送任何事件
-
empty()
该方法创建的被观察者对象发送事件的特点,仅仅执行Complete事件,直接通知完成
-
error()
-
-
延迟创建
-
defer()
直到观察者(observer)订阅时,才会动态创建被观察者对象(observable)&发送事件
-
通过observable工厂方法创建被观察者对象(observable)
-
每次订阅都会得到一个刚创建的最新的observable对象,这可以确保observable对象里的数据是最新的.
i = 20;//首次初始化 Observable<Integer> observable = Observable.defer(new Callable<ObservableSource<Integer>>() { @Override public ObservableSource<Integer> call() throws Exception { return Observable.just(i); //执行i=20; } }); i = 30;//重新赋值 //订阅者订阅事件 得到log是 i=30, observable.subscribe(new Observer<Integer>() { @Override public void onSubscribe(Disposable d) { Log.e(TAG, "连接suber"); } @Override public void onNext(Integer integer) { Log.e(TAG, integer + ""); } @Override public void onError(Throwable e) { } @Override public void onComplete() { Log.e(TAG, "完成整个流程.."); } });
-
-
timer()
作用:快速创建一个被观察者对象(observable) 发送事件的特点:延迟指定时间后,发送一个数值0(Long类型)
本质: 延迟指定时间后,调用一次onNext()事件
-
interval()
快速创建一个被观察者observable,每隔指定时间就发送事件,
本质: 发送事件序列:=从0开始.无线递增1的整数序列
// 参数说明: // 参数1 = 第1次延迟时间; // 参数2 = 间隔时间数字; // 参数3 = 时间单位; Observable.interval(3,1,TimeUnit.SECONDS) // 该例子发送的事件序列特点:延迟3s后发送事件,每隔1秒产生1个数字(从0开始递增1,无限个)
-
intervalRange()
每隔指定时间就发送事件,可以指定发送数据的数量
本质:类似interval() 但是可以指定发送的数据数量
// 参数说明: // 参数1 = 事件序列起始点; // 参数2 = 事件数量; // 参数3 = 第1次事件延迟发送时间; // 参数4 = 间隔时间数字; // 参数5 = 时间单位 Observable.intervalRange(3,10,2, 1, TimeUnit.SECONDS) //1. 从3开始,一共发送10个事件; // 2. 第1次延迟2s发送,之后每隔2秒产生1个数字(从0开始递增1,无限个)但是仅仅发送10次
-
range()
连续发送多个事件类似于intervalRange,区别在于没有延迟
// 参数说明: // 参数1 = 事件序列起始点; // 参数2 = 事件数量; // 注:若设置为负数,则会抛出异常 Observable.range(3,10) // 该例子发送的事件序列特点:从3开始发送,每次发送事件递增1,一共发送10个事件
-
rangeLong()
类似于range区别在于该方法支持long类型
// 参数说明: // 参数1 = 事件序列起始点; // 参数2 = 事件数量; // 注:若设置为负数,则会抛出异常 Observable.rangeLong(3L,10) // 该例子发送的事件序列特点:从3L开始发送,每次发送事件递增1,一共发送10个事件
-
无线轮训请求网络
//执行interval的每隔三秒的轮询.
Observable.interval(3, TimeUnit.SECONDS).doOnNext(aLong -> {
//开始retrofit请求
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://fy.iciba.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
API api = retrofit.create(API.class);
Observable<Model> request = api.getRange("Training request");
request.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Model>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Model model) {
model.toString();
Log.e(TAG, model.toString());
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
}).subscribe(new Observer<Long>() {//观察者订阅事件 开始执行延迟事件
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Long aLong) {
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
}
});
变换操作符
作用
对整个序列中的事件/整个事件进行加工处理(变换操作),使得其转换为不同的事件/整个事件序列
类型
-
Map();
-
作用:对被观察者(observable)发送的每个事件都通过指定函数处理,从而变换为另外一种事件 即被观察者发送的时间转换为任意类型事件
-
引用场景:数据类型的转换
-
具体使用: 从整形转给字符串类型
Observable.create((ObservableOnSubscribe<Integer>) emitter -> { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); }).map(integer -> "使用 Map变换操作符 将事件" + integer + "的参数从 整型" + integer + " 变换成 字符串类型" + integer) .subscribe(s -> Log.e(TAG, s)); //简化版的 subscribe(new observer<string>) //没有执行onCompelete和onError
-
-
FlatMap()
作用:将被观察者发送的时间序列进行拆分&单独转换,在合并成一个新的事件序列,最后在进行发送.
原理: 为事件序列中的每个事件都创建一个Observable对象;
-
将对每个原始事件转换后的新事件都放入到对应observable对象;
-
将新建的歌observable都合并到一个新建的,总的observable对象;
-
新建的,总的observable对象,将新合并的事件序列发送给观察者observer
-
新合并生成的事件序列是无序的,即与旧序列发送事件的序列无关
Observable.create((ObservableOnSubscribe<Integer>) emitter -> { emitter.onNext(1); emitter.onNext(2); emitter.onNext(3); }).flatMap((Function<Integer, ObservableSource<String>>) integer -> { List list = new ArrayList(); for (int i1 = 0; i1 < 3; i1++) { list.add(i1); } return Observable.fromIterable(list); }).subscribe(s -> { Log.e(TAG, s); });
-
-
ConcatMap()
类似于FloatMap 但是合并后的新事件序列是有序的,顺序和原来数据一致.
Observable.create((ObservableOnSubscribe<Integer>) emitter -> emitter.onNext(1)) .concatMap((Function<Integer, ObservableSource<String>>) integer -> { List list = new ArrayList(); for (int i1 = 0; i1 < 3; i1++) { list.add(i1); } return Observable.fromIterable(list); }).subscribe(s -> { Log.e(TAG, s); });
-
Buffer()
定期从观察者(Observable)需要大宋的事件中获取一定数量的事件,&放入到缓存区中,最终发送
应用场景: 缓存被观察者发送的事件,
Observable.just(1, 2, 3, 4, 5, 6, 7).buffer(3, 1).subscribe(new Observer<List<Integer>>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(List<Integer> integers) { Log.e(TAG, "缓存区里的事件数量" + integers.size()); for (int i1 = 0; i1 < integers.size(); i1++) { Log.e(TAG, "事件=:" + i1); } } @Override public void onError(Throwable e) { } @Override public void onComplete() { } });
网络请求嵌套回调
功能描述: 进行多次的网络请求.
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://fy.iciba.com/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build();
API api = retrofit.create(API.class);
Observable<Model> range = api.getRange();
Observable<Model> range2 = api.getRange2();
range.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.doOnNext(model ->
Log.e(TAG, model.toString())
).observeOn(Schedulers.io()).flatMap(model -> range2)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(model -> Log.e(TAG, model.toString()), throwable ->
Log.e(TAG, "登录失败"+throwable.getMessage())
);
12-17 03:04:01.434 4460-4460/com.yishion.demo_count E/RxJavaTranslation: Model{status=1, content=ContentBean{from='en-EU', to='zh-CN', out='登录个人信息', vendor='tencent', err_no=0}}
12-17 03:04:03.554 4460-4460/com.yishion.demo_count E/RxJavaTranslation: Model{status=1, content=ContentBean{from='en-EU', to='zh-CN', out='登记个人资料', vendor='tencent', err_no=0}}
组合/合并操作符
concat/concatArray (按发送顺序执行)
该类型的操作符的作用=组合多个被观察者
作用: 组合多个被观察者一起发送数据,合并后按发送顺序串口执行(concat组合最多观察者数量为4/concatArray则是大于4个)
具体使用
Observable.concatArray(
Observable.just(1, 89),
Observable.just(2, 189),
Observable.just(3, 289),
Observable.just(4, 389),
Observable.just(5, 478)
).observeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(integer ->
Log.e(TAG, "接收到了事件" + integer)
);
merge/mergeArry (按时间线并行执行)
作用: 组合多个被观察者一起发送数据,合并后按时间线并行执行
和concat的区别 同样是组合多个被观察者一起发送数据,单concat操作符合并后是发送顺序串口执行
具体使用:
Observable.concatArray(
Observable.intervalRange(0,5,1,1,TimeUnit.SECONDS),
Observable.intervalRange(6,5,1,1,TimeUnit.SECONDS),
Observable.just(1, 89),
Observable.just(2, 189),
Observable.just(3, 289),
Observable.just(4, 389),
Observable.just(5, 478)
).observeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.subscribe(integer ->
Log.e(TAG, "接收到了事件" + integer)
);
concatDelayError/mergeDelayError
若希望onError事件推迟到其他被观察者发送事件结束后才触发
Observable.concatArrayDelayError(Observable.create(emitter -> {
emitter.onNext(1);
emitter.onNext(2);
emitter.onNext(3);
emitter.onError(new NullPointerException());
emitter.onNext(5);
emitter.onComplete();
}),Observable.just(5,8,9)).subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(Integer integer) {
Log.e(TAG,"接收到了事件"+integer);
}
@Override
public void onError(Throwable e) {
Log.e(TAG, "对Error事件作出响应");
}
@Override
public void onComplete() {
Log.e(TAG, "对Complete事件作出响应");
}
});
Zip
作用: 合并多个被观察者发送的事件,生成一个新的事件序列,并最终发送
Observable<Integer> observable = Observable.create((ObservableOnSubscribe<Integer>) emitter -> {
emitter.onNext(1);
Thread.sleep(1000);
emitter.onNext(2);
emitter.onNext(3);
emitter.onComplete();
}).subscribeOn(Schedulers.io());
Observable<String> observable2 = Observable.create((ObservableOnSubscribe<String>) emitter -> {
emitter.onNext("A");
emitter.onNext("B");
emitter.onNext("C");
emitter.onNext("E");
emitter.onComplete();
}).subscribeOn(Schedulers.newThread());
Observable.zip(observable, observable2, (integer, s) -> integer + s)
.subscribe(new Observer<String>() {
@Override
public void onSubscribe(Disposable d) {
}
@Override
public void onNext(String s) {
Log.e(TAG, s);
}
@Override
public void onError(Throwable e) {
Log.e(TAG, e.getMessage());
}
@Override
public void onComplete() {
Log.e(TAG, "onComplete");
}
});
合并数据源并且显示
-
方法一 merge时间序列上合并
Observable<String> observable = Observable.just("网络请求"); Observable<String> observable1 = Observable.just("本地缓存"); Observable.merge(observable, observable1).subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(String s) { Log.d(TAG, "数据源有: " + s); result += s + "+"; } @Override public void onError(Throwable e) { Log.d(TAG, "对Error事件作出响应"); } @Override public void onComplete() { Log.d(TAG, "onComplete" + result); } });
-
zip合并
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://fy.iciba.com/") .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build(); API aip = retrofit.create(API.class); Observable<Model> observable = aip.getRange().subscribeOn(Schedulers.io()); Observable<Model> observable1 = aip.getRange2().subscribeOn(Schedulers.io()); Observable.zip(observable, observable1, (model, model2) -> model.toString() + model2.toString()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Observer<String>() { @Override public void onSubscribe(Disposable d) { } @Override public void onNext(String s) { Log.d(TAG, "合并后的数据为: "+s); } @Override public void onError(Throwable e) { Log.d(TAG, "合并出错: "+e.getMessage()); } @Override public void onComplete() { Log.d(TAG, "onComplete"); } }); //subscribeOn改变了调用前序列所运行的线程。 //observeOn 对调用之前的序列默不关心,也不会要求之前的序列运行在指定的线程上 对之前的序列产生的结果先缓存起来,然后再在指定的线程上,推送给最终的subscriber
实现三级缓存 内存->磁盘->网络
String meayCache = null; String diskCache = "我是磁盘数据"; Observable<String> observable = Observable.create(emitter -> { if (meayCache != null) { emitter.onNext(meayCache); } else { emitter.onComplete(); } }); Observable<String> observable1 = Observable.create(emitter -> { if (diskCache != null) { emitter.onNext(diskCache); } else { emitter.onComplete(); } }); Observable<String> observable2 = Observable.just("网络请求"); Observable.concat(observable, observable1, observable2).firstElement().subscribe(s -> Log.d(TAG, "数据源来自于...:" + s), throwable -> Log.e(TAG, throwable.getMessage()) ); // 2. 通过firstElement(),从串联队列中取出并发送第1个有效事件(Next事件),即依次判断检查memory、disk、network // a. firstElement()取出第1个事件 = memory,即先判断内存缓存中有无数据缓存;由于memoryCache = null,即内存缓存中无数据,所以发送结束事件(视为无效事件) // b. firstElement()继续取出第2个事件 = disk,即判断磁盘缓存中有无数据缓存:由于diskCache ≠ null,即磁盘缓存中有数据,所以发送Next事件(有效事件) // c. 即firstElement()已发出第1个有效事件(disk事件),所以停止判断。
联合判断多个事件
//给每个edittext设置被观察者,用于发送监听 使用rxBinding
Observable<CharSequence> nameObservable = RxTextView.textChanges(edName).skip(1);
Observable<CharSequence> ageObservable = RxTextView.textChanges(edAge).skip(1);
Observable<CharSequence> sexObservable = RxTextView.textChanges(edSex).skip(1);
//通过combinelatest()合并事件&联合判断
Observable.combineLatest(nameObservable, ageObservable, sexObservable,
(charSequence, charSequence2, charSequence3) -> {
boolean isNameValid = !TextUtils.isEmpty(edName.getText());
boolean isAgeValid = !TextUtils.isEmpty(edAge.getText());
boolean isSexValid = !TextUtils.isEmpty(edSex.getText());
Pattern pattern = Pattern.compile("^[-\\+]?[\\d]*$");
boolean isAgeNumber = pattern.matcher(edAge.getText()).matches();
return isNameValid & isAgeValid & isSexValid & isAgeNumber;
}).subscribe(aBoolean -> {
Log.e("admin", "提交按钮是否可点击" + aBoolean);
btnSub.setEnabled(true);
}, throwable ->
Log.e("admin", "出现错误" + throwable.getMessage())
);