关于Rx框架的一些小心得

/ 0评 / 0

前言

本文基于:

implementation 'io.reactivex.rxjava2:rxandroid:2.0.2'

implementation 'io.reactivex.rxjava2:rxjava:2.1.10'

Rx回调的一些的一些小测试

在Rx中有Observer以及Observable两个对象。

Observer有onSubscribe、onNext、onError、onComplete等几个回调,分别对应订阅,事件通知,出现错误,以及事件通知完毕。这些回调都是在观察者Observer所在的线程,包括map、onErrorReturn等转换符。大致理解就是Observable在自己的工作线程吭哧吭哧的生产事件,然后将每一个生产出来的事件回调到onNext,生产错误就回调onError等,如果观察者需要对生产的事件进行自己的处理比如map,那么也应该发生在观察者所在的线程。

Observer<String> observer = new Observer<String>() {
            @Override
            public void onSubscribe(Disposable d) {
                SLog.i("onSubscribe");
            }

            @Override
            public void onNext(String s) {
                SLog.i("onNext:" + s);
            }

            @Override
            public void onError(Throwable e) {
                SLog.i("onError");
            }

            @Override
            public void onComplete() {
                SLog.i("onComplete");
            }
        };

Observable在生产事件的时候,也许自己出现了Exception,如果没有onErrorReturn等处理错误结果,那么就直接回调onError,如果onErrorReturn中还是继续出现了Exception,那么最终还是回调onError,但是如果onErrorReturn将错误结果纠正(返回默认数据),那么就会回调onComplete,说了这么多废话,其实就是一句大家都知道的话。onError与onComplete互斥。在一次订阅周期里面只有一个会被回调

Rx中一些其他好玩的回调

如下代码所示,可以发现多了一些好玩的回调,比如doOnSubscribe、doOnNext、doOnError、doOnComplete等,其实与上文提到的一模一样,不过这些回调都会早于响应的onXXX回调,比如doOnSubscribe > onSubscribe.

Observable
	.just("one", "two", "three")
	.subscribeOn(Schedulers.io())
	.observeOn(AndroidSchedulers.mainThread())
	.doOnSubscribe(new Consumer<Disposable>() {
		@Override
		public void accept(Disposable disposable) throws Exception {
			SLog.i("doOnSubscribe");
		}
	})
	.doOnNext(new Consumer<String>() {
		@Override
		public void accept(String s) throws Exception {
			SLog.i("doOnNext:" + s);
		}
	})
	// 这个必须写在doOnError的前面,不然不生效啊
	.onErrorReturn(new Function<Throwable, String>() {
		@Override
		public String apply(Throwable throwable) throws Exception {
			return "default";
		}
	})
	//这个必须写,不然如果被观察者出现error,会导致程序异常
	.doOnError(new Consumer<Throwable>() {
		@Override
		public void accept(Throwable throwable) throws Exception {
			SLog.i("doOnError");
		}
	})
	.doOnComplete(new Action() {
		@Override
		public void run() throws Exception {
			SLog.i("doOnComplete");
		}
	})
	.doOnTerminate(new Action() {
		@Override
		public void run() throws Exception {
			SLog.i("doOnTerminate");
		}
	})
	.doFinally(new Action() {
		@Override
		public void run() throws Exception {
			SLog.i("doFinally");
		}
	})
	.subscribe();

特别说明:

整个订阅流程必须有处理错误的回调,比如直接使用new Observer就必须实现onError,如果使用简写的Disposable subscribe(Consumer<? super T> onNext) 方法订阅,也必须实现onError。不然如果Observable出现了异常,那么会导致io.reactivex.exceptions.OnErrorNotImplementedException

Rx中的错误处理

onErrorReturn:当Observable中发生异常的时候,你有机会返回一个默认值,然后整个订阅流程就中断了,然后回调onComplete。

onErrorReturnItem:这个是onErrorReturn的一种简化形式,直接返回一个对象。

Rx常用场景一

在异步请求之前进行提示,请求完毕取消提示。

对于请求之前进行提示,我们可以在onSubscribe/doOnSubscribe中进行处理,毕竟每一次请求是从订阅开始的。

对于请求完毕取消提示,我们可能为正常结束(onComplete),也可以能出现了错误(onError),也可能是请求半路被取消掉了(取消请求不会回调onComplete/onError),所以这里就需要找一个必定回调的方法。查看源码可以发现,doOnTerminate会在onComplete、onError之前被回调,但是对于请求取消的情况不会被回调如果想三种情况都被回调到,那么需要使用doFinally方法

现在我们知道了onSubscribe/doOnSubscribe对应一切的开始,doFinally对应一切的结束,这样我们就可以用来控制提示的显示/隐藏了。

onSubscribe/doOnSubscribe回调在订阅的线程,如果在主线程订阅,那么这个回调就在主线程中,doFinally如果没有使用Disposable.dispose取消掉请求,那么默认和订阅发生的线程为同一线程,但是如果Disposable.dispose在另一个线程被调用,那么doFinally就在调用Disposable.dispose的线程中被回调,所以这里要注意doFinally所在的线程,不然可能在非主线程操作UI

Rx常用技巧一

我们都知道,当使用异步操作的时候,最需要注意的就是即时的取消掉请求,不然可能导致内存泄露等情况。CompositeDisposable这个类就是Rx提供用来管理订阅的。

CompositeDisposable mCompositeDisposable = new CompositeDisposable();
//添加订阅到管理
mCompositeDisposable.add(disposable);
//取消所有添加的订阅
mCompositeDisposable.dispose();

Rx常见的Exception

OnErrorNotImplementedException:这个上面已经介绍过了,主要是因为Observer没有实现onError方法,所以当Observable中出错以后没有处理错误的位置,导致Crash。

UndeliverableException:这个主要是由于Observable发送了一个事件并回调了Observer的onNext方法,可是在onNext中出现了异常,所以导致Crash。

UndeliverableException:这个主要是由于Observer取消订阅了Observable,可是Observable还在生成事件,并且在生成事件的过程中出现了一个Exception。常见的情景是Observable在进行网络请求,但是Observer取消了订阅,这时Observable出现了一个没有被catch的Exception,那么这个Exception则会导致程序Crash。

其他

其实本篇博客只是介绍了一些很小的细节,不过在开发中也是必须要清楚了解的部分,写了半天测试代码,留作笔记。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注