[译] Data Binding 库使用的经验教训

简介: Data Binding 库(下文中以『DB 库』词语来指代)提供了一个灵活强大的方式来绑定数据到 UI 界面。但是要用一句陈词滥调:『能力越大,责任越大』,仅仅是使用数据绑定,并不意味着你可以避免成为一个优秀 UI 开发者。

原文地址:Data Binding — Lessons Learnt
原文作者:Chris Banes
译文出自:掘金翻译计划
本文永久链接:github.com/xitu/gold-m…
译者:Mirosalva
校对者:DevMcryYu


image.png

Data Binding 库(下文中以『DB 库』词语来指代)提供了一个灵活强大的方式来绑定数据到 UI 界面。但是要用一句陈词滥调:『能力越大,责任越大』,仅仅是使用数据绑定,并不意味着你可以避免成为一个优秀 UI 开发者。
过去的几年我一直在 Android 开发中使用 data binding 库,本文会写出我这一路上了解到的与它有关的一些内容细节。

尽可能使用 bindings

自定义 binding adapter 是一种给 View 控件轻松提供自定义功能的好方法。和许多开发者一样,我对 binding adapter 研究得稍微深入,最终总结出一套包含 15 种不同用途的适配器的类集。
最糟糕的实践是这类适配器,它们生成格式化的字符串并设置到 TextViews 控件,这些适配器通常仅在同一个布局文件中使用:
虽然这可能看起来很聪明,但是有三大缺点:

1.优化它们的过程太痛苦。除非你把代码组织得非常好,否则你可能会有一个包含所有适配器方法的大文件,这与代码内聚和解耦原则相违背。

2.你需要使用 instrumentation 工具来做测试。根据定义,你的 binding adapter 不会有返回值,它们接收一个输入参数后设置 view 的属性。这就意味着你必须使用 instrumentation 来测试你的自定义逻辑,这样会使得测试变得既缓慢又难以维护。

3.自定义 binding adapter 代码(通常)不是最佳选项。如果你查看内建文本绑定[参考这里],你将会看到已经做了许多检查来避免调用 TextView.setText(),这样就节省了被浪费的布局检测。我觉得自己陷入了这样的思维困境:DB 库将会自动优化我的 view 更新。它确实可以做到,但仅限于你使用被谨慎优化的内建 binding adapter的情况。

相反的,把你的方法的逻辑抽象为内聚类(我称之为文本创建者类),然后将它们传递给 binding。这样你就可以调用你的文本创建者类并使用内建 view binding:
这样我们可以从内建的绑定操作过程中提高效率,并且我们可以非常轻松地对创建格式化字符串的代码进行单元测试。

让你的自定义 binding 适配器变得高效

如果你确实需要使用自定义适配器,因为你所需的功能不存在,请尽量使其变得高效。我的意思是使用所有标准的 Android UI 优化:尽可能避免触发测量/布局操作。
这可以像检查当前使用的视图以及你设置的内容一样简单。这里有一个我们为 android:drawable 重新实现了标准 ImageView adapter 的样例:
遗憾的是,视图并不总是能够显示我们需要检查的状态。这里有一个在 TextView 上设置切换最大行的示例。它通过改变 TextView 的 maxLines 属性以及一个延时布局转换(android.view.ViewGroup)来实现切换。

16a15efc95cd45be.gif

之前 binding adapter 比较简单并且总是设置了 maxLines 属性和一个点击监听对象。TextView 在 setMaxLines() 被调用后总会触发一次布局,这就意味着每次 binding adapter 启动,一次布局就会被触发。
让我们改变这个情况。由于此功能与 TextView 是完全分开的(我们只是在单击时使用不同的值调用 setMaxLines()),我们需要将引用存储为当前状态。幸运的是,『DB 库』为我们提供了一个手工方式去在 binding adapter 中接收状态。通过提供参数两次:第一个参数接收当前值,第二个参数接收新值。
所以这里我们只需比较当前的和新的 collapsedMaxLines 值。如果值实际发生了改变,我们才去调用 setMaxLines() 等方法。
编辑按: 感谢 Alexandre Gianquinto 在评论中提到『double parameters』功能。

谨慎对待你提供的变量

我一直在慢慢的重新设计 Tivi,使用类似 MVI 的东西,使用优秀的 MvRx 库来使它变得规范化。这在实践中意味着我的 fragment/view 订阅到 ViewModel对象,并且接收 ViewStates 的实例。这些实例包含所有用于显示 UI 的必要状态。
这是一个展示 Tivi(链接)中类的样例:
你可以看到它仅仅是一个简单的数据类,包含了 UI 需要在一个 TV 秀界面上显示的所有细节 UI 元素。
听起来像是传递我们的 data binding 实例对象的完美选项,让我们的 binding 表达式来去更新 UI,对吧?好吧这确实有效,但是有一些需要注意的地方,这是由于『DB 库』的工作机制。

在 data binding 中你通过 标签声明了输入,然后在书写 binding 表达式时在 view 属性处引用了这些输入变量。当任何被依赖的变量发生变化,『DB 库』都会运行你的 binding 表达式(接着会更新 view)。这个变化检测就是你可以免费获取的很棒的优化。

所以回到我的场景,我的布局最终看起来是这样的:

所以我最终获取一个包含所有 UI 状态的全局 ViewState 实例,并且你可以想象出这些状态经常会发生变化。UI 状态的任何轻微变化都会产生一个全新的 ViewState,并被传递到我们的 data binding 实例。

所以问题是什么?由于我们只有一个输入变量,所有的 binding 表达式将会引用变量,这就意味着『DB 库』将无法自由选择运行哪个表达式。在实际过程中,这意味着每次变量变化(不管多小的变化)发生时所有的 binding 表达式都会运行。

这个问题与 MVI 这点无关,特别是它只是组合状态的 artifact,与data binding 结合在一起使用。

那么你能怎么做呢?

有种替代方法是在布局中显式声明 ViewState 中的每个变量,然后显式传递组合状态实例中的值,如下所示:

这显然会使开发人员维护和同步更多的代码,但它确实意味着『DB 库』可以优化去运行哪些表达式。如果你的 UI 状态不经常变化(可能在创建时有一些次)并且变量数量较少时,我会推荐使用此模式。

我个人一直在布局中使用单个变量,传入我的 ViewState 实例,并依赖于我们的视图绑定合理地运行。这就是为什么让视图绑定变得高效非常重要。

另一个需要注意的是 Tivi 是 RecyclerView 的重度使用者,还有 Epoxy 和 Data Binding,意思就是在 DiffUtil 中会额外有一些变化相关的计算发生。所以如果你的 UI 也有大量的 RecyclerView 组成,你可以类似上文描述不费事地获取计算这方面的优化。

小步迭代

希望这篇文章强调了一些可以优化数据绑定实现方案中的一些小事。了解『DB 库』的内部机制可以帮助你提高数据绑定效率,并提高你的 UI 性能。


作者:Mirosalva
链接:https://juejin.im/post/5cb1a5dfe51d456e831f68eb
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

目录
相关文章
|
Android开发
Android开发教程 - 使用Data Binding(七)使用BindingAdapter简化图片加载
本系列目录 使用Data Binding(一)介绍 使用Data Binding(二)集成与配置 使用Data Binding(三)在Activity中的使用 使用Data Binding(四)在Fragment中的使用 ...
1095 0
问题集锦:使用CMake部署Qt应用程序:set_target_properties、get_target_property
问题集锦:使用CMake部署Qt应用程序:set_target_properties、get_target_property
225 0
|
JavaScript 前端开发 开发者
从规范的角度看 this 丢失 —— 详解 Reference Type
从规范的角度看 this 丢失 —— 详解 Reference Type
96 0
从规范的角度看 this 丢失 —— 详解 Reference Type
|
数据可视化 Python
【pypi开源项目文档】终极秘诀应对rst解析错误:The description failed to render in the default format of reStructuredText
前面雷学委给大家缕一缕了如何开发一个python库并导入运行, 基本完成了一个初步的库,还支持了命令行工具的发布。
432 0
【pypi开源项目文档】终极秘诀应对rst解析错误:The description failed to render in the default format of reStructuredText
HANA report里默认filter的工作机制
HANA report里默认filter的工作机制
83 0
HANA report里默认filter的工作机制
|
Android开发 开发工具
Android开发教程 - 使用Data Binding(二)集成与配置
本系列目录 使用Data Binding(一)介绍 使用Data Binding(二)集成与配置 使用Data Binding(三)在Activity中的使用 使用Data Binding(四)在Fragment中的使用 使用Data Binding(五)数据绑定 使用Data Binding(六.
1108 0
|
IDE 开发工具 Android开发
Android开发教程 - 使用Data Binding(五)数据绑定
本系列目录 使用Data Binding(一)介绍 使用Data Binding(二)集成与配置 使用Data Binding(三)在Activity中的使用 使用Data Binding(四)在Fragment中的使用 ...
1022 0
|
Android开发 数据格式 XML
Android开发教程 - 使用Data Binding(八)使用自定义Interface
本系列目录 使用Data Binding(一)介绍 使用Data Binding(二)集成与配置 使用Data Binding(三)在Activity中的使用 使用Data Binding(四)在Fragment中的使用 ...
1116 0