RXJava介绍及简单使用

1,204 阅读3分钟

##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);
                    }
                });
    }
}

测试结果

网络.png

###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;
    }
}