离线下载
PDF版 ePub版

极客学院团队出品 · 更新于 2017-09-25 14:00:37

RxAndroid 基础:第一部分

译者:李鑫

原文:RxAndroid Basics: Part 1

本文为极客学院Wiki组织翻译,转载请注明出处。

时间:2016.3.8

欢迎!你可能对 RxJava 的这个扩展以及它在 Android 上的应用感到有些好奇。或许你已经见识过它的一些用途,但可能感觉有些疑问,想要一些详细的介绍,那么本文肯定能解决你的疑问。

当我第一次接触 RxJava 时,多数都是采用货物崇拜式编程的方式。有时是奏效的,但我对一些基础概念缺乏正确认识。缺乏优秀的范例来告诉我到底是怎么回事,所以让我感到非常失望。为了能够真正、完整地了解 RxJava,我进行了很多探索,其中包含了大量的试错过程。

为了避免亲爱的读者你继续彷徨,我决定把自己的探索成果用一些例子展示出来。希望它们能帮助你正确使用 RxJava 开发 Android 应用。

这些例子是一个全功能范例应用中的一部分。在每个例子的开端,将给出范例代码所在的 Activity 的链接。这些例子分成两部分。在第一部分中,集中解决如何使用 RxJava 异步加载数据的问题;第二部分介绍更多高级的使用模式。

一些必要的概念

在我们开始正式介绍之前,先来介绍一些基本概念。RxJava 其核心是两种对象:Observable 对象及 Observer 对象。Observable 对象用来“发射”值,而 Observer 对象则通过“订阅” Observable 对象来观察这些对象。

当 Observable 对象发射值,或者当 Observable 对象说明已经发生错误,或当 Observable 对象通知没有要发射的值时,Observer 对象就会采取相应操作。三种操作都被封装在 Observer 接口内。相应的函数为onNext()onError()onCompleted()

知道了这些,先让我们来看一些例子。

范例 1:基本范例

先让我们用一个 Activity 对象简单地显示一列颜色。我们将制作一个 Observable 对象,让它先发射单个值,再发射一列字符串,然后结束。我们将使用 Observable.just() 方法,该方法将创建一个 Observable 对象,以便当一个 Observer 对象订阅它时,Observer 的 onNext() 方法会被立刻调用,并使用提供给 Observable.just() 的参数。然后调用 onComplete(),因为 Observable 没有其他值可发射。

注意,getColorList() 是一个非阻塞式的方法调用。这一点现在可能不太重要,但稍后会继续讲到它。

下面,建立一个观察 Observable 对象的 Observer 对象:

这里有些玄机。如上文所述,一旦利用 subscribe() 方法订阅了 Observable 对象,下列步骤将依次发生:

  1. onNext() 方法被调用,释放的颜色列表被设置为适配器数据。
  2. 因为没有其他数据(利用 Observable.just(),只让 Observable 对象发射一个单个值 ),调用了onComplete()

在考虑订阅时,多思考一下 Observable 对象是有好处的。实际上,Observable 对象就是按照订阅行为定义的。一定要记住这一点,因为这个概念将来会很有用。将来会再次讨论它。

Observable 对象就是根据订阅行为定义的。

在本例中,我们完全不用考虑当 Observable 完成后发生的事情,所以将 onComplete() 方法保持为空。另外,也不可能抛出错误,所以将 onError() 也保持为空。

所有这些做法可能看上去有些不必要。将颜色列表直接设置在适配器中。但是先让我们来考虑一些有趣的问题。

范例 2:异步加载

利用一个 Activity 异步加载一个最喜欢的电视节目列表。异步加载数据可能是 RxJava 在 Android 中最常用的用途了。首先,创建 Observable 对象。

在上面的例子中,使用 Observable.just() 来创建 Observable 对象,因此对于这个例子,我们完全可以同样采用类似 Observable.just(mRestClient.getFavoriteTvShows()) 的方式来做。

但我们不能这么做,因为 mRestClient.getFavoriteTvShows() 是一个阻塞网络调用。如果还使用 Observable.just()mRestClient.getFavoriteTvShows() 就会立刻求解,阻塞 UI 线程

Observable.fromCallable() 方法提示了两种关键内容:

  1. 创建发射值的代码直到 Observer 被订阅才运行。
  2. 创建代码可以在不同线程下运行。

两种属性一会儿就派上用场,先来订阅 Observable:

先分开来讲解各个函数。subscribeOn() 基本上影响的是上面创建的 Observable 对象。Observable 将正常运行的所有代码,包括针对订阅运行的代码,将运行在不同的线程上。这意味着我们可调用的对象——包括对getFavoriteTvShows() 的调用——中的逻辑将在不同的线程上运行。但它运行在哪个线程上?

在本例中,规定代码运行在 “IO 调度器” (Schedulers.io())。 现在我们只需认为调度器是一个不同的线程即可。实际上还得介绍更多的内容,但对于我们的目的而言,这种描述已经足够用了。

但现在还是遇到了一点小问题。因为 Observable 被设置运行在 IO Scheduler 上,这意味着将在 IO Scheduler 上与 Observer 进行交互。这就是一个问题,因为 onNext() 方法将在 IO Scheduler 上被调用。onNext() 中的代码会一些视图中调用方法。视图方法只能在 UI 线程上调用。

解决方法很简单。只需让 RxJava 明白,我们希望在 UI 线程上观测这个 Observable,比如在 UI 线程上调用 onNext() 回调。在 observeOn() 中指定另外一个 scheduler,也就是 AndroidSchedules.mainThread()(UI 线程的调度器)所返回的调度器。

最后一点要注意的是调用 subscribe()。这一点很重要,因为只有当实际订阅一些东西时,可回调对象中的代码才会运行。知道了我上文中所说的“Observable 对象就是根据订阅行为定义的”的意思了吧?

这还不是最后要做的。mTvShowSubscription 是什么?当 Observer 订阅一个 Observable,就会创建一个 Subscription。Subscription 表示的是 Observer 与 Observable 之间的连接。有时我们需要保持这种连接。先来看看 Activity 的 onDestroy() 方法中的一些代码。

如果之前你曾经处理过 Android 的线程,那么肯定知道有这样一种巨大隐患:如果 Activity 被回收后,线程结束(或永不结束)执行,会产生什么问题。这将造成一堆问题,比如内存泄露和空指针异常(NullPointerExceptions)等。

订阅可以帮我们解决这个问题。这个过程相当于说:“Observable,这个 Observer 不想再接收到你的发射了,不要和这个Observer再连接了。”通过调用 unsubscribe() 来实现。调用完 unsubscribe() 后,之前创建的 Observer 不会再接收发射,从而避免了 Activity 被回收后,线程结束作业(或根本不结束)所带来的一堆问题。

最难的部分已经介绍完了,让我们做一个小小的总结。

  • Observable.fromCallable() 目的是延迟创建 Observable 所要发射的值。这通常适用于需要从 UI 线程中创建 Observable 所要发射的值时。
  • subscribeOn() 在特定线程中运行值创建代码,该线程不是 UI 线程。
  • observeOn() 在一个合适的线程中观察 Observable 的发射值,也就是主 UI 线程。
  • 我们必须经常让 Observer 取消订阅,以防止出现利用 Observable 异步加载时出现的问题。

范例 3:使用 Single

还是用 Activity 加载一列最喜欢的电视节目,但是这一次换一种简单的实现方式。Observable 是非常不错的,但在很多情况下使用它们是有点过头了。比如,在上面两个例子中,我们只发射了一个单值,从来没用过 onComplete() 回调。

其实,还有一种简单的 Observable:Single。Single 和 Observable 差不多。但是跟 Observable 有三种回调 onComplete()onNext()onError() 的情况不同,它只有两种回调:onSuccess()onError()

下面用 Single 再做一遍上面的例子,首先创建一个 Single。

然后订阅它。

这个过程看起来非常熟悉。调用 subscribeOn(),确保对 getFavoriteTvShows() 的调用在 UI 线程外运行。调用 observeOn() 确保在 UI 线程发射 Single 的结果。

与其使用 Observer,我们将使用 SingleSubscriber 类。它跟 Observer 非常类似,但只包含上面提到的两种方法:onSuccess()onError()。SingleSubscriber 对应 Single,就像 Observer 对应 Observable。

订阅 Single 同样也产生了一个 Subscription 对象。这种订阅和范例 2 中一样,同样也需要用 onDestroy() 取消订阅。

最后一点。这一范例中还添加了错误处理代码。所以,如果 mRestClient 调用抛出了错误,就会获得 onError 回调。我建议你实际编写并调试一下这个例子,看看在不使用 mRestClient.getFavoriteTvShows,而是使用 mRestClient.getFavoriteTvShowsWithException() 时会出现什么情况。

最后总结

这就是第一部分的内容了。我希望这些例子能对你有所帮助。接着看第二部分的介绍吧,这些复杂的范例会让你收获更多的。

作者简介

Kurtis Nusbaum 是一位任职于 Uber 的移动应用开发者,他非常喜欢长跑。他的社交网站账号为: FacebookLinkedIn。哦,还有他的Github 账号。如果你觉得 Kurtis 是一位好的合作者,可以通过kcommiter@gmail.com联系他。