RxJava的使用基础教学 三

在第一章中,我们了解了RxJava的基本框架,第二章中我们知道操作符可以变得如何强大。但也许你可能仍然有些迟疑,要让你信服还远远不够。那么本章将会介绍一些有关RxJava的其他优点。
Error Handling
在此之前我们已经大大忽略了onComplete()和onError()。它们在Observable停止释放数据时被调用,无论是成功完成还是失败出错。而Subscriber可以监听到这两个方法:


Observable.just("Hello, world!")
    .map(s -> potentialException(s))
    .map(s -> anotherPotentialException(s))
    .subscribe(new Subscriber<String>() {
        @Override
        public void onNext(String s) { System.out.println(s); }

        @Override
        public void onCompleted() { System.out.println("Completed!"); }

        @Override
        public void onError(Throwable e) { System.out.println("Ouch!"); }
    }); 

假设potentialException()和anotherPotentialException()都由可能抛出异常,而Observable将会在onComplete()或onError()结束释放。那么这一段代码要么会输出Completed,要么会输出Ouch。这里有一些需要注意的地方:

1 在整个数据流的任何地方一旦抛出异常,onError()方法就会被调用。这会令异常处理变得轻松多了,我完全可以在每个方法后面添加异常处理方法。
2 操作符可以不用处理异常。你可以将异常交给Subscriber,让它决定如何处理。
3 你明确知道Subscriber会在何时结束接收数据项。
了解这些会使错误处理比以前更加轻松,因为如果用回调你不得不在每个回调里都加上错误处理方法,这不仅仅会带来重复代码也意味着每个回调必须明确怎样处理错误,也就表示你的回调代码必须紧紧依附于调用者。
用RxJava,你的Observable甚至都不用知道遇到异常错误该如何处理。你的其他任何操作符都不用处理错误,他们会在出现严重错误时直接跳过。你可以把你所有的错误处理都交给Subscriber。


Schedulers

如果你的Android应用有网络请求的话,那么你不得不将这个耗时的操作放在其他线程上,但在Android上多线程处理是很困难的,因为你必须保证在正确的线程上运行正确的代码,一旦有误程序就会崩溃。一个经典的异常就会在你尝试修改主线程上的View的时候抛出来。

使用RxJava,subscribeOn()用来决定你的observer代码在哪个线程运行,observeOn()用来决定你的Subscriber会在哪个线程运行(下面的代码为例,意思是根据url请求图片会在其他线程执行,而bitmap获取下来之后会在主线程上执行设置图片,简而言之,请求操作在subscribeOn内定义在哪条线程执行,当结果来了之后会根据observeOn内的设置来决定subscribe内的操作会在哪条线程上执行)。

myObservableServices.retrieveImage(url)
    .subscribeOn(Schedulers.io())
    .observeOn(AndroidSchedulers.mainThread())
    .subscribe(bitmap -> myImageView.setImageBitmap(bitmap)); 

这里需要注意的地方是subscribeOn内的设置,可以设置很多种线程,但常用的有三种,源码如下:

[java]  view plain copy
  1. private final Scheduler computationScheduler;  
  2. private final Scheduler ioScheduler;  
  3. private final Scheduler newThreadScheduler;  

那么该这三种的不同在于,第一种会有一个固定大小的线程池,线程池的大小等于有效processor个数,然后再使用最近最少使用原则来选择worker。第二种和第三种每次请求都会新起一个线程,而两者区别仅仅是前者有缓存机制后者没有。

Subscriptions

有一件事情我一直没有提到,当调用Observable.subscribe()它会返回一个Subscription。它代表了你的Observable和subscriber的连接:

Subscription subscription = Observable.just("Hello, World!")
    .subscribe(s -> System.out.println(s)); 

换句话说,你可以在适当的时候得到这个连接进行绑定或解绑:

subscription.unsubscribe();
System.out.println("Unsubscribed=" + subscription.isUnsubscribed());
// Outputs "Unsubscribed=true" 

关于RxJava很好的一个地方就是解绑意味着停止整条链,无论什么时候正在做什么,一旦解绑就会立即终止,仅此而已。这里需要解释的是,这个数据链的理解,你可以把整个数据链从开头到结尾完全连接起来去思考,有入口也有出口,数据从某个操作符进入后,中间经过了多个操作符的处理方法最终返回出口,接下来就分别发送给订阅者,即subscribe()的内容。一般的操作符都会返回Observable<T>类型,而这里的Subscription是最终出口subscribe的返回类型,因此一旦拿到它便可以随时随地进行进行数据链的控制。

Conclusion

Keep in mind that these articles are an introduction to RxJava. There's a lot more to learn than what I presented and it's not all sunshine and daisies (for example, read up on backpressure). Nor would I use reactive code for everything - I reserve it for the more complex parts of the code that I want to break into simpler logic.

Originally, I had planned for this post to be the conclusion of the series, but a common request has been for some practical RxJava examples in Android, so you can now continue onwards to part 4. I hope that this introduction is enough to get you started on a fun framework. If you want to learn more, I suggest reading the official RxJava wiki. And remember: the infinite is possible.

Many thanks to all the people who took the time to proofread these articles: Matthias Käppler, Matthew Wear, Ulysses Popple, Hamid Palo and Joel Drotos (worth the click for the beard alone).

1 This is one reason why I try to keep my Subscriber as lightweight as possible; I want to minimize how much I block the main thread.

2 Deferring calls to observeOn() and subscribeOn() is good practice because it gives the Subscriber more flexibility to handle processing as it wants. For instance, an Observable might take a while, but if the Subscriber is already in an I/O thread you wouldn't need to observe it on a new thread.

3 In part 1 I noted that Observable.just() is a little more complex than just calling onNext() and onComplete(). The reason is subscriptions; it actually checks if the Subscriber is still subscribed before calling onNext().

你可能感兴趣的:(RxJava的使用基础教学 三)