##RXJAVA简介
rxjava的官方介绍: RxJava 一个在 Java VM 上使用可观测的序列来组成异步的、基于事件的程序的库。
个人总结
1、异步: 是基于观察者模式的
2、线程切换
3、丰富的操作符
重要对象
RxJava 有以下三个基本的元素:
- 被观察者(Observable)
- 观察者(Observer)
- 订阅(subscribe)
##简单示例介绍
// 第一步:初始化Observable
Observable.create(new ObservableOnSubscribe() {
@Override
public void subscribe(@NonNull ObservableEmitter e) throws Exception {
Log.e(TAG, "Observable emit 1" + "\n");
e.onNext(1);
Log.e(TAG, "Observable emit 2" + "\n");
e.onNext(2);
Log.e(TAG, "Observable emit 3" + "\n");
e.onNext(3);
e.onComplete();
Log.e(TAG, "Observable emit 4" + "\n" );
e.onNext(4);
}
}).subscribe(new Observer() { // 第三步:订阅
// 第二步:初始化Observer
private int i;
private Disposable mDisposable;
@Override
public void onSubscribe(@NonNull Disposable d) {
mDisposable = d;
}
@Override
public void onNext(@NonNull Integer integer) {
i++;
if (i == 2) {
// 在RxJava 2.x 中,新增的Disposable可以做到切断的操作,让Observer观察者不再接收上游事件
mDisposable.dispose();
}
}
@Override
public void onError(@NonNull Throwable e) {
Log.e(TAG, "onError : value : " + e.getMessage() + "\n" );
}
@Override
public void onComplete() {
Log.e(TAG, "onComplete" + "\n" );
}
});
##主要的使用场景
rxjava 网络错误重试
rxjava 定时器
线程切换(替代handler)
心跳
rxjava 网络错误重试
<pre>
<code>
/**
* 指定订阅、注销、回调线程
* @param o
* @param s
* @param <T>
*/
public <T> void toSubscribe(Observable<T> o, Subscriber<T> s) {
// 指定subscribe发生在IO线程
o.subscribeOn(Schedulers.io())
//在IO线程注销
.unsubscribeOn(Schedulers.io())
// 指定回调发生在主线程
.observeOn(AndroidSchedulers.mainThread())
.retryWhen(new RetryWithDelay(3, 3000))
.subscribe(s);
}
<code>
</pre>
主要代码:
.retryWhen(new RetryWithDelay(3, 3000))
解释:采用retryWhen操作符针对异常情况进行重试,重试次数为3次,间隔时间为3s
RetryWithdelay代码
public class RetryWithDelay implements
Func1<Observable<? extends Throwable>, Observable<?>> {
private final int maxRetries;
private final int retryDelayMillis;
private int retryCount;
public RetryWithDelay(int maxRetries, int retryDelayMillis) {
this.maxRetries = maxRetries;
this.retryDelayMillis = retryDelayMillis;
}
@Override
public Observable<?> call(Observable<? extends Throwable> attempts) {
Log.e(TAG, "重新获取token");
return attempts
.flatMap(new Func1<Throwable, Observable<?>>() {
@Override
public Observable<?> call(Throwable throwable) {
if (++retryCount <= maxRetries) {
// When this Observable calls onNext, the original Observable will be retried (i.e. re-subscribed).
Log.e(TAG, "get error, it will try after " + retryDelayMillis
+ " millisecond, retry count " + retryCount);
return Observable.timer(retryDelayMillis,
TimeUnit.MILLISECONDS);
}
// Max retries hit. Just pass the error along.
return Observable.error(throwable);
}
});
}
}
测试结果
###rxjava 定时器
开启定时器
public void start() {
stop();
countDownTaskDisposable = Observable.interval(0, 10, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
// 获取主控服务器状态
getRobotServiceState();
// 获取控制服务器状态
getServiceState();
// 连续计时
tickCount();
}
});
}
关闭定时器
public void stop() {
if (countDownTaskDisposable != null) {
countDownTaskDisposable.dispose();
countDownTaskDisposable = null;
}
}
主要在项目中的使用场景:替代时间、机器人电量更新线程,及主界面更新显示时间、机器人数据。
优点:
1、rxjava提供定时器的操作符
2、rxjava提供线程调度器,可直接指定观察者和被观察者的触发线程
3、基于2,可省略原先项目中的handler操作
rxjava 线程切换(替代handler及new Thread)
原先全局handler的代码
/**
* 延时发送
* work thread --> main thread
* @param r
* @param delay
*/
public static void postDelayed(Runnable r, long delay) {
checkNotNull(sHandler);
sHandler.postDelayed(r, delay);
}
/**
* main thread--> work thread
* @param r
*/
public static void postWork(Runnable r) {
checkNotNull(sHandler);
sWorkHandler.post(r);
}
rxjava的代码
/**
* 主线程做操作
* @param uiTask
*/
public static void doOnUIThread(UITask uiTask){
Observable.just(uiTask)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(uiTask1 -> uiTask.doOnUI());
}
/**
* 主线程做操作, 带延迟方法
* @param deley 延时时间,单位为ms
* @param uiTask
*/
public static void doOnUIDeleyThread(int deley, UITask uiTask){
Observable.just(uiTask).delay(deley, TimeUnit.MILLISECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe((Consumer<? super UITask>) o -> {
uiTask.doOnUI();
});
}
/**
* io线程做操作
* @param threadTask
*/
public static void doOnThread(ThreadTask threadTask){
Observable.just(threadTask)
.observeOn(Schedulers.io())
.subscribe(threadTask1 -> threadTask1.doOnThread());
}
使用
启动子线程操作
RxJavaThreadUtils.doOnThread(() -> voiceMiddlewareUtils.startUnitNlp(asrResultStr));
发送到主线程操作
RxJavaThreadUtils.doOnUIDeleyThread(3 * 1000, ()->pageJump(staticIp) );
###心跳 现在心跳采用线程池实现,是没有问题的。只是考虑到rxjava自身就是一个线程调度器,他里面就封装了线程池的使用。所以采用rxjava来实现。
/**
* 启动心跳
*/
public void start() {
if (countDownTaskDisposable != null) {
countDownTaskDisposable.dispose();
}
countDownTaskDisposable = Observable.interval(0, 10, TimeUnit.SECONDS)
.subscribeOn(Schedulers.io())
.subscribe(new Consumer<Long>() {
@Override
public void accept(Long aLong) throws Exception {
heartbeatCheck();
}
});
}
/**
* 发送心跳
*/
private void heartbeatCheck() {
Log.d("DC","发送心跳" + Thread.currentThread().getName());
byte[] commandBytes = SocketCodeApi.heartbeatData();
SocketDataForwardFactory.getInstance().sendDataServer(commandBytes);
}
/**
* 关闭心跳
*/
public void stop() {
if (countDownTaskDisposable != null) {
countDownTaskDisposable.dispose();
countDownTaskDisposable = null;
}
}