Rxjava线程切换实战
- 异步线程区域
Schedulers.io()
:代表io流操作,网络操作,文件流,耗时操作
Schedulers.newThread()
: 比较常规的,普普通通
Schedulers.computation()
: 代表CPU 大量计算 所需要的线程 AndroidSchedulers.mainThread()
: 专门为Android main线程量身定做的- 给上游分配多次,只会在第一次切换,后面的不切换了(忽略)
- 给下游分配多次,每次都会去切换
RxJava背压模式
背压模式的由来:
RxJava1.X的时候,还没有背压模式, 我们的上游不停的发射,我们的下游处理不过来,就会照成内存泄漏
RxJava2.X之后,增加背压模式,Observable Flowable(解决背压)
Observable — > Flowable(解决背压)什么时候用Observable<—>Observer, 什么使用Flowable<—>Subscriber ?
答:发射的事件,大量的事件(1000个),并且考虑到下游处理不过来,就需要使用Flowable
背压策略
BackpressureStrategy.ERROR
如果池子满了,就会抛出异常BackpressureStrategy.BUFFER
如果池子慢了,“等待”下游来接收事件处理BackpressureStrategy.DROP
如果池子满了,就会把后面发射的事件丢弃(不常用)BackpressureStrategy.LATEST
只存储 128个事件(不常用)
背压例子
Flowable.create(new FlowableOnSubscribe<Integer>() {
@Override
public void subscribe(FlowableEmitter<Integer> e) throws Exception {
// todo 1 上游不停的发射大量事件
for (int i = 0; i < Integer.MAX_VALUE; i++) {
e.onNext(i); // todo 1
}
e.onComplete();
}
}, BackpressureStrategy.BUFFER)
.subscribeOn(Schedulers.io()) // 给上游分配异步线程
.observeOn(AndroidSchedulers.mainThread()) // 给下游分配 主线程
.subscribe(
// 完整版本的下游 观察者
new Subscriber<Integer>() {
@Override
public void onSubscribe(Subscription s) {
subscription = s;
// 如果同步的 不执行此s.request();,(等待下游,发现下游没有去处理)会抛出异常, 外界在调用subscription.request(10); 无效果
// 如果是异步的,不执行此s.request();,不会发生异常(上游不会等待下游)不会发生异常, 外界在调用subscription.request(10); 是ok的
// s.request(100); // 只请求输出 100次,给下游打印
}
@Override
public void onNext(Integer integer) {
// todo 2 下游阻塞了 处理不过来
try {
Thread.currentThread().sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
// TODO 一旦下游处理了一次上游的事件,缓存池 - 1
Log.d(TAG, "onNext: " + integer);
}
// onError: create: could not emit value due to lack of requests 上游还有剩余的事件,无法处理,因为没有去请求
@Override
public void onError(Throwable t) {
Log.d(TAG, "onError: " + t.getMessage());
}
@Override
public void onComplete() {
Log.d(TAG, "onComplete: ");
}
}
);
RxJava之Flowable讲解
Flowable
和Observerable
使用几乎一致,依葫芦画瓢就可。- 切断下游的方式略有不同,如下:
Observable
–Observer
下游 –onSubscribe(Disposable d)
切断下游(水管)Flowable
—Subscriber
下游 –onSubscribe(Subscription s)
取出(s.request(5)
)事件 给下游接收使用
RxJava配合Retrofit
需求:一行代码写完需求流程 (从上往下)
- 请求服务器,执行注册操作(耗时)切换异步线程
- 更新注册后的所有 注册相关UI - main 切换主线程
- 请求服务器,执行登录操作(耗时)切换异步线程
- 更新登录后的所有 登录相关UI - main 切换主线程
MyRetrofit.createRetrofit().create(IRequestNetwork.class)
// 1.请求服务器注册操作 // todo 第二步 请求服务器 注册操作
.registerAction(new RegisterRequest()) // Observable<RegisterResponse> 上游 被观察者 耗时操作
.subscribeOn(Schedulers.io()) // todo 给上游分配异步线程
.observeOn(AndroidSchedulers.mainThread()) // todo 给下游切换 主线程
// 2.注册完成之后,更新注册UI
/**
* 这样不能订阅,如果订阅了,就无法执行
* 3 马上去登录服务器操作
* 4.登录完成之后,更新登录的UI
*
* 所以我们要去学习一个 .doOnNext(),可以在不订阅的情况下,更新UI
*/
.doOnNext(new Consumer<RegisterResponse>() { // 简单版本的下游
@Override
public void accept(RegisterResponse registerResponse) throws Exception {
// todo 第三步 更新注册相关的所有UI
// 更新注册相关的所有UI
tv_register_ui.setText("xxx");
// .......
}
})
// 3.马上去登录服务器操作 -- 耗时操作
.subscribeOn(Schedulers.io()) // todo 分配异步线程
.flatMap(new Function<RegisterResponse, ObservableSource<LoginResponse>>() {
@Override
public ObservableSource<LoginResponse> apply(RegisterResponse registerResponse) throws Exception {
// 还可以拿到 注册后的响应对象RegisterResponse
// 执行耗时操作
// 马上去登录服务器操作 -- 耗时操作
Observable<LoginResponse> observable = MyRetrofit.createRetrofit().create(IRequestNetwork.class)
.loginAction(new LoginRequest()); // todo 第四步 马上去登录服务器操作 -- 耗时操作
return observable;
}
})
// 4.登录完成之后,更新登录的UI
.observeOn(AndroidSchedulers.mainThread()) // // todo 给下游切换 主线程
.subscribe(new Observer<LoginResponse>() {
@Override
public void onSubscribe(Disposable d) {
// todo 第一步
progressDialog.show();
}
@Override
public void onNext(LoginResponse loginResponse) {
// 更新登录相关的所有UI
// todo 第五步 更新登录相关的所有UI
tv_login_ui.setText("xxxx");
// ...........
}
@Override
public void onError(Throwable e) {
}
@Override
public void onComplete() {
// todo 第六步
progressDialog.dismiss(); // 结束对话框 ,整个流程完成
}
});
看RxJava另外一种的执行流程
初始点 开始点 订阅
onSubscribe
registerAction(new RegisterRequest())
doOnNext
更新注册后的 所有UIflatMap
执行登录的耗时操作- 订阅的观察者 下游
onNext
方法,更新所有登录后的UI progressDialog.dismiss()
Java泛型的上下限
由于RxJava大量的使用到了泛型,所有学习
如果我们不指定泛型类型,默认就是Object,Object的扩展集
? super F
下限:F or F 所有父类 都可以,所以属于把下面的类型限限制了,下面的类型不能低于F,不能是F的子类,否则编译不通过。? extends F
上限:F or F 所有子类 都可以,所有属于把上面的类型给限制了,上面的类型不能高于F,不能是F的父类,否则编译不通过。
一句话记住(? super F: F 或者 F的所有父类 都可以, ? extends F: F 或者 F的所有子类都可以)- 可写模式
<?super F>
可写,不完全可读
因为设定了下限为F类型,所以F和F类型的的子类一定都是一个F,它们都是可写的。但是F的父类的写入就不是合法的,因为这个泛型可能就是F,不能用一个子类的引用指向一个父类的对象。因为没有上限,所以你只能保证能读到Object的子类。 - 可读模式
<? extends F>
可读,不可写
因为不能确定这个泛型的下限,自然不可写。但这是可读的,因为读到的一定是F或F的子类。