咱们项目采用的是 kotlin && DataBinding 处理的,可能你会疑问,既然用的是 kotlin,为啥没有用 kotlinx?新的页面固然是用的 kotlinx 啦,但咱们有至关庞大的历史代码,而且咱们的通用 adapter 其实也是基于 DataBinding 来封装的。因此,咱们仍是不得不来讨(吐)论(槽)一下这个 DataBinding 的坑。事实上,这个问题在我当年面试字节跳动的时候就被问及过。android
这是一个很是开放性的问题,因此看到这篇文章的小伙伴必定得带一个有色眼镜进行审视,下面会尽量地列举中笔者遇到过的坑,固然能力有限,有可能很多东西并非 DataBinding 的问题,须要你们一块儿来甄别并进行补充。git
DataBinding 是早些时候 Google 推出来的一个支持库,只要敢于解决咱们代码中频繁出现的 findViewById()
问题,在此以前,我相信大部分人都听过或者使用过 Butterknife,截止目前,该库都已经更新到 10.1.0 了,并且做者是 JakeWharton 大神,实为至关好用。github
但咱们今天不对 Butterknife 进行过多的评论,而转移到咱们的主角 DataBinding。面试
对于 DataBinding 的使用和介绍这里就不作讲述了,建议你们仍是直接到 官方文档 进行查阅学习,今天在这儿,主要和你们分享讨论一下在笔者 1 年多的 DataBinding 中踩过的一些坑。我想这些 tips 确定不是所有,而且有些实际上是我的误操所致,无论怎么说,咱们今天就舍弃对它的赞美,吐槽吐槽这个 DataBinding。缓存
oh,这应该是使用 DataBinding 的小伙伴们最最最大的坑点了,你甚至必定在各类技术轮胎和开发交流群中见过一些小伙伴对它的深恶痛绝。无论你代码中有了什么错误,你必定收到的错误日志是一大堆 DataBinding 生成的类找不到。服务器
可能很是多的小伙伴会对此保持疑问,这不,真正的错误都在 build 日志的最后能看到么?实在没有看到,你也能够在控制台输入 ./gradlew build --stacktrace
查看到详细日志。组件化
但事实真的如此么?有没有小伙伴经历过无论你怎么查看日志都找不到真正的错误代码的。性能
我想必定有!虽然咱们通常都要求对 commit 保持「少许屡次」的原则,但这并不能保证咱们时刻都得严格遵照,在部分业务很是紊乱的时候,咱们并不但愿常常作 commit,由于每一次 commit,咱们也得作一次编译确认当前的代码没有任何语法问题。而对于代码量庞大、尤为是还受各类历史缘由组件化不够完全的项目,一次编译基本就可让你去吃一个饭了。我司的项目就是如此,受限于历史缘由,组件化作的并不完全,致使本地编译在没有命中缓存的状况下至少得 10 分钟,这仍是在 16G 的 mac pro 上。并且大多数人的电脑可能配置还更低,在编译的时候很难作其余和工做相关的事情。学习
为了处理这个编译问题,我司不得不编写一个编译脚本,把编译操做都在服务器上进行处理,在作了一系列优化操做后,在没命中缓存的状况下编译 debug 包仍是须要 4.5 分钟,固然如今在编译中咱们能够作其余有意思的事情了。gradle
好像前面这两段说了不少可有可无的东西,可是!我真正想要表达的是,这时候出现了错误,而且日志没法对错误进行定位,你会发现很是痛苦,你可能已经改动了数十个文件,新建了很多 XML,由于没法定位到日志,你不得不一行一行的进行语法检查。
我在这个问题上体验过编码两小时,查编译失败问题花费时间更多的尴尬状况,一般来讲,这样的错误都不容易发现,我深深的记住我有一次由于组件化历史问题,不得不把一个组件代码 move 到另一个组件,而后就发生了不可预料的错误的悲痛场景。当你 stash
改动后就能够编译,但 pop
出来就错误的时候,你才会知道什么是手段极其残忍。
OK,目前对于这样的状况,仍是有所总结,这种状况 95% 是 XML 代码的问题,你能够直接检查 XML 了。
咱们使用 DataBinding 的时候,必然会喜欢它的双向绑定操做。在 XML 里面直接作一些简单的逻辑处理,这样的操做让咱们的代码变得很是简洁,而且能够省去 findViewById()
带来的没必要要的性能损耗。但这样的操做让后续维护功能代码的人很是痛苦。
咱们的代码里面就有至关部分的这样的代码,部分页面逻辑很是复杂,好比一个商品详情页,会牵扯到很是大量的信息展现和各类促销秒杀状态,还有很多的动效,这时候很多逻辑放在 XML 里面后,后续维护的同事在处理产品改动的时候,必定在心中暗自谩骂。
一般来讲,我习惯于把这些复杂的逻辑放置在咱们的 Java 代码中。就目前来看,在代码中查看这些复杂的交互逻辑驾轻就熟很多。
早些时候,我连续犯过两次低级错误,因此对这个问题记忆深入。咱们能够发现,XML 里面支持咱们用相似 @{}
这样的方式去为 TextView
设置显示内容,但在 XML 里面咱们并无检测机制,因此极易出现本来你这个是一个 Number
类型的值,编译器却当作一个 resourceId
进行处理而报错。实际上,在代码里面设置编译器是会直接报错的。
在咱们项目的早期代码中,XML 里面的命名规范基本是 xxx_xxx_xxx 这样的格式,但在 DataBinding 里面为咱们生成的变量却采用的是驼峰命名法,这致使咱们根据一个控件 id 去对应 class 里面寻找的时候,还得本身更改成驼峰命名法命名的名字,这一度让咱们感到很是不适,因此咱们后面的代码 XML 命名规范就跟着变成驼峰命名法了。这可能和命名规范有些许出入,不过咱们坚信适合本身的,才是最好的理念。
前面说到,咱们平时会采用服务器编译,因此此前有出现过 XML 文件里面的某个属性设置在本地编译不过,但在服务器上甚至其余同事的电脑上能够编译的问题。老实说,目前我并无找到真正的缘由,我姑且把这个问题甩锅给了此前作这个的同事。我后续更改了他的实现方式才让这个问题获得妥善处理,但至今没有明白问题出在哪里,由于那样的方式我认为自己代码是没有什么问题的。惋惜我如今没有时间去寻找这个代码,大概是设置一个公用的 onClickListener
的问题。
咱们一般会用到 @BindingAdapter 方式来作一些公用逻辑,而不是直接去把逻辑放在页面经过设置属性来使用它,这样就会出现这些公用逻辑比较难维护,固然,这极有多是咱们项目的历史问题,但我以为这算是一个坑点了。不知道有没有人出现这样的属性在 XML 里面没有提示的状况。就像你自定义 View Styleable 名字不惟一同样。
这个问题我以前尚未发现,由于咱们每一个模块都用到了 DataBinding,因此认为每一个模块的 gradle
都设置上 DataBinding 的配置,并不算什么使人能够吐槽的事,但看起来这个问题挺严重的,因此也在这分享给你们。转自 wanAndroid 上面 xujiafeng 的回答}
DataBinding在多模块开发的时候,有这样一个机制: 若是子模块使用了 DataBinding,那么主模块也必须在 gradle 加上配置,否则就会报错; 若是主模块和子模块都添加上了 DataBinding 的配置,那么在编译时,子模块的 XML 文件产生的 Binding 类除了在本身的 build 里会有一份外,在主模块下也会有一份。 那么,若是主模块与子模块都有一个 layout 根目录的 activity_main.xml,主模块生成的 ActivityMainBinding 会是根据子模块的文件生成的!这种状况咱们还能够经过让主模块和子模块使用不一样的命名,那么下面这个问题就更要命了:
若是子模块的某个 XML 文件使用了一些第三方的控件,那么主模块因为也会生成这个文件的 Binding 类,而且其会有第三方控件的引用,这时候因为主模块没有引入这些控件,就会报错,解决办法是在子模块应用第三方控件的时候,使用 API 的方式应用,这样主模块就坚定引用到了这些第三方控件,这是这样违背了解耦的原则。
哎,我的能力有限,就想到哪儿说到哪儿了。可能有很多其实并非 databinding 的坑,是我的使用问题,还往明白的人能直接指出。PS:再给我一个机会,我不想在用 Databinding。
但愿有其余槽点或者认为上面的东西是有更好的处理方式的小伙伴必定要在下面留言,盼复盼复~