在第一节,学习了Rxjava的基本结构,在第二节,我给你展示了操作符的强大之处。但是也许你还是不买账,这些都不足矣说服你。这里有一些其他Rxjava框架应该搞定的技术。
错误处理
至今为止,我们一直忽视了onComplete()和onError()。他们标识了Observable将停止发射内容和为啥停止(不是执行成功了,就是发生了一个无法恢复的错误)
原生的Subscriber有去监听onComplete()和onError()的能力。让我们动手试试:
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结束都会调用onCompleted()或者onError()。因此,程序不是输出“Completed”,就是输出“Ouch”(因为发生了异常)
从这个模式引申出几个重点:
- 一旦有异常,就会调用onError()
这让错误处理变得十分简单,我可以在一个单一的函数中处理每个错误。 - 操作符不需要处理异常
你可以将如何在一堆Observable 链里处理错误遗留到Subscriber 中,因为错误都会跳到onError()方法里面。 - 你可以知道Subscriber完成正在接收的项目
知道一个任务是否已经完成可以帮助你跟踪代码(尽管有可能一个Observable永远不会完成)
我发现这种模式相对于传统的错误处理更加简单。传统的回调中,你不得不在每个回调里进行错误处理,这不光导致代码重复,还意味着每个回调必须知道如何处理错误,回调函数和错误处理耦合度太高了。
在Rxjava这种模式下,你的Observable不必关心错误是如何处理的。你的操作符也不需要关心这些,因为他们将会跳过那些失败。你可以把所有的错误处理留到Subscriber中。
调度器
假设有一个去请求网络资源的安卓应用,它会耗时费很长,所以你需要将它加载到另一个线程中去,那么问题来了。
多线程在安卓应用中比较麻烦,因为你必须确保正确的代码跑在正确的线程上;一旦有错,那你的应用就挂了。一个典型的异常就是你尝试修改主线程中的View(译者注:没学过安卓,不太清楚为什么修改主线程中的View时会发生异常)。
在Rxjava中,你可以通过使用subscribeOn()来告诉Observer应该在哪个线程上跑,然后用observeOn()去告诉Subscriber如何运行。
myObservableServices.retrieveImage(url)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(bitmap -> myImageView.setImageBitmap(bitmap));
太简单了!Subscriber运行在一个I/O线程上之后,所有的一切再运行,结束以后,主线程上被发生了View操作。
最赞的地方在于我能够在任何一个Observable上附加subscribeOn()和observeOn()。他们仅仅只是操作符。我不需要担心Observable或它之前的操作符都干了什么。
在类似于使用AsyncTask的模式中,我不得不设计我的代码哪些部分我需要同步,在rxJava中,我的代码保持不变—它已经加上了一系列的同步。
订阅
有件事我没告诉你。当你调用Observable.subscribe(),他返回的是一个Subscription,它代表了你的Observable和Subscriber之间的联系。
Subscription subscription = Observable.just("Hello, World!")
.subscribe(s -> System.out.println(s));
你可以利用Subscription取消两者的联系。
subscription.unsubscribe();
System.out.println("Unsubscribed=" + subscription.isUnsubscribed());
// Outputs "Unsubscribed=true"
RxJava处理取消订阅漂亮的地方在于它停止了链。如果你有一堆复合的操作链,不论当前执行的是什么代码,利用unsubscribe都将会终止链,其他工作都不需要做。
结论
记住这些文章只是在介绍RxJava。还有更多的内容需要学习。rxJava不是万能药,不需要所有的事情都靠他去做——我只是想化繁为简。
起初,我计划这篇文章是这个系列的最后一篇,但是网友普遍要求需要在安卓上实践RxJava,所以你可以继续看这个系列的第四部分。我希望这个介绍可以足够吸引你去开始尝试这个有趣的框架。如果你想学到更多,我建议你去读官方的rxJava wiki。
非常感谢花大量时间校对这一系列文章的人:Matthias Käppler, Matthew Wear, Ulysses Popple, Hamid Palo 和Joel Drotos