场景一: 单请求异步处理
由于在Android UI线程中不能做一些耗时操作,比如网络请求,大文件保存等,所以在开发中经常会碰到异步处理的情况,我们最典型的使用场景是RxJava+Retrofit处理网络请求
MyService myService = retrofit.create(MyService.class);
myService.getSomething()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateUI, this::showError);
为了使代码看起来简洁点,这边还使用了lambda表达式, updateUI 和 showError 需要在当前类中实现,比如:
public void updateUI(Data data){
//TODO something
}
public void showError(throwable t){
//show error msg
}
场景二: 多异步请求连续调用
这种场景其实也很常见,我们做用户头像编辑的使用,一般就会有三个请求需要连续调用:
- 请求头像上传的地址
- 上传头像
- 更新用户信息
在平时的代码里,我们需要一步步callback嵌套下来,代码冗长太难看,而且不好维护,使用RxJava链式调用处理代码逻辑就会非常清晰
Observable.just(1)
.map(this::task1)
.map(this::task2)
.map(this::task3)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateUI, this::showError);
这里的just发送的固定值1,没有实际意义,只是我觉得这样更信息
你也可以用Observable.create创建observable。
场景三: 多异步请求合并处理
有时候在项目中,我们会碰到组合多个请求的结果后,再更新UI的情况,比如我们项目中就有一个从多个请求地址获取通知数据,然后在APP上再按时间顺序组合后展示的需求,这时候我们就可以用RxJava的zip函数来处理了
MyService myService = retrofit.create(MyService.class);
Observable o1 = myService.getNotification1();
Observable o2 = myService.getNotification2();
Observable.zip(o1,o2, this::combiNotification)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::updateUI, this::showError);
public List<Notification> combiNotification(List<Notification> n1, List<Notification> n2){
//TODO 合并通知列表
}
zip函数会等待两个请求都完成后,调用我们的合并方法combiNotification,等合并处理后再回调subscribe中的方法。
场景四: 定时轮询
RxJava还特别适合对定时轮询任务的处理, 一种典型的例子就是APP提交了一个任务给后台异步处理,假设后台处理需要1-2分钟左右,我们需要定时到后台查询进度,并更新到UI上, 传统的做法是用Handler的postDelay方法,用RxJava实现的话就会非常简洁
Subscription subscription = Observable.interval(2, TimeUnit.SECONDS)
.map(this::getProgress)
.takeUntil(progress -> progress != 100)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<Long>() {
@Override
public void onCompleted() {
//TODO finished
}
@Override
public void onError(Throwable e) {
}
@Override
public void onNext(int progress) {
//TODO update progress
}
});
我们以定时2秒查询一次,直到进度progress=100为止,自动终止轮询。
定时心跳
场景描述:
- 一个发送数据出口
- 定时循环发送一个数据
- 当需要发送一个数据临时插入一个数据从出口发送
需要用到的操作符
repat 重复发送 delay 延时发送 just 快速创建被观察者,插入心跳数据 mergeDelayError 合并发送,错误延时
流程
主要是创建两个被观察者,一个负责心跳的发送,另外一个负责数据的发送
实现代码
重复执行某个动作直到成功,或失败,或超时
场景描述:
- 重复执行某个动作
- 成功后中断继续执行操作
- 错误继续执行
- 未响应发出超时错误,并继续执行
- 达到超时次数,中止执行
需要用到的操作符
distinct 过滤 timeout 超时发出错误 retryWhen 错误重试 zipWith 合并(用于统计错误重试次数) delay 延时(用于发送错误后等待一段时间继续发送)
流程
发出动作请求,等待结果,过滤结果。
- 结果为onError立马重新发出动作请求
- 等待指定时间没有结果,发出超时onError然后重新发出动作请求
- 结果为成功结果终止动作请求
- 直到成功为止,或者超过重试的指定次数
实现代码
任务流(循环)
场景描述
- 一个动作完成后才执行下一个动作
- 所有动作完成后重复继续执行
需要用到的操作符
concat 连接操作符(只能连接9个,但是可以嵌套) repat 循环
流程
使用flatmap创建一个基本异步任务,用concat实现连接,用reapt实现循环
实现代码
以上各种RxJava方法都是异步耗时调用,考虑到Activity的退出时请求还没有完成,我们需要在Activity的OnDestroy方法中取消RxJava调用,以及一个实战步骤。更多有关RxJava的学习或Android核心技术的进阶 可以> 前往
传送直达↓↓↓ :link.juejin.cn/?target=htt…
文末
rx的优势:
- 线程切换,不需要像handler那样 请求与结果在不同地方
- 链式编程, 复杂的逻辑形成一条链,消灭回调地狱、迷之缩进,并且可以在期间做各种线程切换
后面所有的线程切换都是用封装好的方法