Unlimited WordPress themes, graphics, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Android SDK
Code

Android APP中的RxJava 2:RxBinding和RxLifecycle

by
Difficulty:IntermediateLength:LongLanguages:

Chinese (Simplified) (中文(简体)) translation by Zhang Xiang Liang (you can also view the original English article)

RxJava是将响应式编程引入到Android平台的最受欢迎的库之一,在这个系列三篇文章中,我已经展示了如何在自己的Android项目中使用该库。

在 Get Started With RxJava 2 for Android这篇文章中,我们先看了什么是RxJava以及它为Android开发人员提供了什么,然后再创建一个Hello World APP,演示了RxJava的三个核心组件:一个Observable,一个Observer和一个订阅。

Reactive Programming Operators in RxJava 2这篇文章中,我们研究了如何使用运算符执行复杂的数据转换,以及如何组合OperatorsSchedulers以最终在Android上实现多线程体验。

我们还介绍了RxAndroid,这是一个专门用于帮助你在Android项目中使用RxJava的库,但RxAndroid还有许多要探索的地方。所以,在这篇文章中,我将专注于RxAndroid系列库。

与RxJava很相似,RxAndroid在其版本2中进行了大规模的修改。RxAndroid团队决定对库进行模块化,将其大部分功能转移到专用的RxAndroid附加模块中。

在本文中,将展示如何设置和使用一些最受欢迎和功能强大的RxAndroid模块,包括处理listeners, handlers和TextWatchers的库,以及让你能够将任何Android UI事件转换为Observable的东西。

由于不完整的订阅引起的内存泄漏是Android APP中使用RxJava的最大缺点,所以我将展示如何使用处理订阅过程的RxAndroid模块。在本文结尾,你将了解如何在任何ActivityFragment中使用RxJava而避免任何RxJava相关的内存泄漏的风险。

创建更多的响应式Android UI

对UI事件(如点击,滑动和文本输入)的响应几乎是安卓APP开发的基本部分,但是处理Android UI事件并不是特别直截了当。

你通常会使用listeners, handlers, TextWatchers和其他组件等的组合来响应UI事件。这些组件中的每一个都需要编写大量的样板代码,更糟糕的是,实现这些不同组件的方式并不一致。 例如,你可以通过实现OnClickListener来处理OnClick事件:

但这与实现TextWatcher的方式完全不同:

这种一致性的缺乏可能会为代码增加很多复杂性。如果你有UI组件依赖于其他UI组件的输出,那么事情会变得更加复杂! 即使是一个简单的用例,例如要求用户将其名称输入到EditText,以便个性化TextViews的文本内容,而TextViews需要嵌套回调,这是非常难以实现和维护的。 (有人将嵌套回调称为“回调地狱”)

显然,处理UI事件的标准化方法有可能大大简化代码,而RxBinding就是这样的库,它通过提供绑定,使你能够将任何Android View事件转换为一个Observable。  

一旦你将view事件转换为Observable,它将发射数据流形式的UI事件,你就可以订阅这个数据流,这与你订阅其他Observable的方式一样。

由于我们已经了解了如何使用Android标准捕获点击事件OnClickListener,我们来看看如何使用RxBinding实现相同的结果:

这种方法不仅更简洁,而且是一种标准的实现方式,你可以将其应用于整个APP中发生的所有UI事件。例如,捕获文本输入与捕获点击事件相模式一样:

使用RxBinding的示例APP

你可以看到RxBinding如何简化APP的UI相关代码,让我们创建一个演示绑定操作的APP。我要添加一个View,它取决于另一个的View的输出,这样来演示RxBinding如何简化UI组件之间创建关系。

这个APP将包括:

  • 当点击Button时显示Toast
  • 一个检测文本变化的EditText
  • 一个TextView实时显示EditText的内容。

项目设置

创建一个Android Studio项目,然后打开module级的build.gradle文件,添加最新版本的RxBinding库的依赖关系。为了使用lambdas表达式,更新build.gradle文件来支持这个Java 8功能:

当你使用多个RxJava库时,可能会在编译时遇到Duplicate files copied in APK META-INF/DEPENDENCIES这个错误。如果遇到此错误,解决方法是通过将以下内容添加到module级的build.gradle文件来去掉这些重复的文件:

创建 MainActivity的布局

同步Gradle文件,然后创建布局,包括Button,EditText和TextView:

编写绑定事件

现在,我们来看看如何使用这些RxBinding来捕获APP需要响应的各种UI事件。对于初学者,声明imports并定义MainActivity类。 

现在,你可以开始添加绑定来响应UI事件了。RxView.clicks方法用于绑定点击事件。创建一个绑定,在点击按钮时显示吐司:

接下来,当EditText内容变化后,使用RxTextView.textChanges()方法来更新TextView的内容。

运行结果如下.

The default version of our RxBinding user interface

将APP安装到物理Android智能手机或平板电脑或兼容的AVD上,然后与各种UI元素进行交互。APP应该按照正常的点击事件和文本输入做出响应,所有这些都不需要listener,TextWatcher或回调。

RxBinding user interface

支持库视图的RxBinding

虽然核心的RxBinding库为标准Android平台的所有UI元素提供了绑定,但也有RxBinding同级模块为Android的各种支持库的一部分提供了绑定。

如果你已经在项目中添加了一个或多个支持库,那么通常也需要添加相应的RxBinding模块。

这些同级模块遵循一个简单的命名约定,可以很容易识别相应的Android的支持库:每个同级模块只需拿到支持库的名称,然后将com.android替换为com.jakewharton.rxbinding2:rxbinding。

  • compile com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'
  • compile 'com.jakewharton.rxbinding2:rxbinding-support-v4:2.0.0'
  • compile 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7:2.0.0'
  • compile 'com.jakewharton.rxbinding2:rxbinding-design:2.0.0'
  • compile 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7:2.0.0'
  • compile 'com.jakewharton.rxbinding2:rxbinding-leanback-v17:2.0.0'

如果使用的是Kotlin,那么还可以为每个RxBinding模块提供Kotlin版本。要访问Kotlin版本,只需添加-kotlin到库的名称,因此:

变为:

View事件转换为Observable后,所有这些事件都将作为数据流被发射出去。正如你所见,你可以订阅这些流,然后执行任何需要此特定UI事件触发的任务,例如显示Toast或更新TextView。 然而,也可以将RxJava的大量运算符应用到这个observable的流中,甚至将多个运算符链接在一起,对UI事件进行复杂的转换。

操作符太多以至于在一篇文章中讨论不完(官方文档列出了所有的操作符),但是在处理Android UI事件时,有一些操作符特别有用。

debounce()操作符

首先,如果你担心不耐烦的用户可能会重复点击UI而导致可能会弄迷糊你的APP,那么你可以使用debounce()运算符过滤出快速连续发出的任何UI事件。

在下面的示例中,指定上次点击事件间隔至少500毫秒后才对OnClick事件作出响应:

publish()操作符

你还可以使用publish()运算符让多个listeners监听同一个view,这在传统Android开发中很难实现。

publish()运算符将标准Observable转换为可连接的Observable。只要第一个观察者订阅常规的Observable,它就开始发射数据流,但是通过connect()运算符连接后,Observable将不会发出任何内容,除非收到明确的指示。 这是一个机会,订阅多个观察者,一旦第一次订阅发生,不必立即开始发射数据。

创建完所有订阅后,只需应用connect()运算符,observable就会开始向所有分配的观察者发送数据。  

避免APP内存泄漏

正如我们在本系列中所看到的,RxJava可以创建更具响应性的、交互式的Android APP,实现相同结果,其代码比使用Java更少。然而,在Android APP中使用RxJava存在一个最大的缺点,即不完整的订阅会导致内存泄漏。

当Android系统尝试销毁包含正在运行的ObservableActivity时,会发生内存泄漏。由于observable正在运行,其观察者仍然会持有对该Activity的引用,因此系统将无法对此Activity进行垃圾回收。

由于Android的Activity在每次设备配置更改时都会被破坏并被重建,因此APP可能会在用户在纵向和横向屏幕切换时以及每次打开和关闭设备的键盘时创建重复的Activity

这些Activities将在后台挂起,可能永远不会被回收。由于Activities是大的对象,这可能会导致严重的内存管理问题,尤其是Android智能手机和平板电脑的内存限制。 大量内存泄漏和有限内存的组合可能会导致Out Of Memory 错误。

RxJava内存泄漏可能会对APP的性能造成破坏,但是现在有一个RxAndroid库允许你在APP中使用RxJava而无需担心内存泄漏。

由Trello开发的RxLifecycle库提供了生命周期处理API,你可以使用它们来限制Activity或Fragment中的Observable。一旦建立了此连接,RxLifecycle将终止observable的序列以响应该observable所分配的ActivityFragment中的生命周期事件。 这意味着你可以创建一个observable,当Activity或Fragment被销毁时,它将自动终止。

请注意,我所的说是终止序列,而不是取消订阅。虽然在管理订阅/取消订阅过程的上下文中经常谈到RxLifecycle,但在技术上它不取消订阅观察者。 相反,RxLifecycle库通过发出onComplete()或者onError()方法终止observable序列。 当你取消订阅时,observer停止接收来自其可观察的通知,即使该observable仍在发射数据。如果你特别要求取消订阅行为,那么你需要实现自己。

使用RxLifecycle

要在Android项目中使用RxLifecycle,请打开module级的build.gradle文件,并添加最新版本的RxLifeycle库以及RxLifecycle Android库:

然后,在你想使用该库的ActivityFragment中,要么继承RxActivityRxAppCompatActivityRxFragment,并添加相应的import语句,例如:

当涉及绑定ObservableActivityFragment的生命周期时,你要么指定observable应终止的生命周期事件,要么让RxLifecycle库决定何时终止observable 序列。

默认情况下,RxLifecycle将在辅助生命周期事件中终止observable,所以如果你在Activity的onCreate()方法期间订阅了observable,则RxLifecycle将在该Activity的onDestroy()方法终止observable序列。 如果你在FragmentonAttach()方法中订阅,那么RxLifecycle将在onDetach()方法中终止在该序列。

使用RxLifecycleAndroid.bindActivity进行设置:

或者,你可以指定lifecycle事件,在该事件中RxLifecycle应该使用RxLifecycle.bindUntilEvent终止Observable序列。

在这里,我指定在onDestroy()方法中终止observable序列:

Android Marshmallow权限

我们将要看的最后一个库是RxPermissions,它旨在帮助你使用RxJava与Android 6.0中引入的新权限模型。该库还允许你发出权限请求并处理相同位置的权限结果,而不是在一个地方请求权限,然后在Activity.onRequestPermissionsResult()中分别处理其结果。

首先将RxPermissions库添加到build.gradle文件中:

然后创建RxPermissions实例:

然后使用以下公式通过RxPermissions库发出权限请求:

发出权限请求的地方是至关重要的,因为申请权限的对话框在屏幕上,而Activity随时可能被破坏并被重建,比如用户纵向和横向屏幕之间切换而引起的配置变化。 如果发生这种情况,那么你的订阅可能无法重新创建,这意味着你不会订阅RxPermissions observable并且不会收到用户对权限请求对话框的响应。为了保证你APP收到用户的响应,总是在初始化阶段申请权限,比如在Activity.onCreate(),  Activity.onResume()或View.onFinishInflate()中。

APP功能需要多个权限并不罕见。例如,发送短信通常需要有SEND_SMS和READ_CONTACTS权限。RxPermissions库提供了发出多个权限请求的简洁方法,然后将用户的响应组合成一个false(一个或多个权限被拒绝)或true(所有权限被授予)响应,然后可以相应地做处理。

通常,你需要触发一个响应UI事件的权限请求,例如用户点击菜单项或按钮,因此RxPermissions和RxBiding是两个在一起工作的库。

将UI事件作为observable,并使用RxPermissions申请权限可以让你用几行代码就完成大量工作:

结语

从本文中你学到了很多东西,你可以从Android APP中删除大量样板代码 - 使用RxJava处理所有应用程序的UI事件,并通过RxPermissions申请权限。我们还研究了如何在Activity或者Fragment中使用RxJava而不用担心不完整订阅引起的内存泄漏。

我们已经在本系列中探讨了一些最受欢迎和有用的RxJava和RxAndroid库,但如果你还想看看RxJava可以为Android开发人员提供其他库,请查看其他RxAndroid库。也可以在GitHub上找到 comprehensive list of additional RxAndroid libraries

与此同时,请查看我们在Envato Tuts +上的一些其他Android开发文章!

关注我们的公众号
Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.