专栏首页京东技术当MVVM遇到Databinding,京东工程师实现1+1>2

当MVVM遇到Databinding,京东工程师实现1+1>2

作 者 简 介

甘明涛——Android软件开发工程师

5年以上开发经验,对架构设计有较深刻认知,负责京东商城购物车的开发和设计工作,热衷研究新技术。

>>>>

引言

MVVM和Databinding是当前非常流行且实用的框架和工具,相信大家已经对MVC、MVP、MVVM框架以及Databinding有一定的了解。本文主要介绍一个基于Databinding封装的MVVM框架,并结合当下非常火的Android Architecture Components库,实现一种更简单的MVVM框架。

>>>>

一、MVVM-Databinding框架背景

开篇先来了解下MVVM和Databinding及其各自优势,才能说明我们为什么要不辞辛劳的合二为一,并希望最终达到1+1>2的效果。

>>>>

1、MVVM框架简介及优势

MVVM框架类似于早期的MVC和近期的MVP,但是比起这两个更为强势。MVVM中的ViewModel层类似MVP的Presenter层,所需要做的完全就是跟逻辑相关的代码,完全不会涉及到UI。当数据变化,直接驱动UI的改变,中间省去了MVP中冗余的接口。

同时,在ViewModel层编写代码中,要求开发者需要将每个方法尽可能的做的功能单一,不与外部有任何的引用或者是联系,无形中提高了代码的健壮性,方便了后期的单元测试。如果想进一步了解的话,可以看《Android软件设计框架——MVC、MVP、MVVM》

下图形象说明了MVC、MVP、MVVM的进化过程:

>>>>

2、数据绑定框架DataBinding简介及优势

DataBinding是谷歌出台的工具,可以实现UI和数据的绑定。我们的View和ViewModel通过DataBinding可以实现单向绑定或双向绑定,做到UI和数据的相互监听。

同时开发者的任务分配也就很明确了,负责ViewModel的小伙伴完全不用考虑UI如何实现,很大程度上提高了代码的开发效率和后期出问题跟踪的准确性,针对这些好处,采用MVVM进行代码开发还是非常有必要的。

当然,实现MVVM框架不是只能用DataBinding,可以实现UI和数据绑定的框架都可以,像开源框架RoboBinding等,甚至也可以使用Android Architecture Components库中的Livedata实现手动绑定UI和数据。

如果您对Databinding不太熟悉,可以看下我写的这篇入门文章(https://www.jianshu.com/p/9fb720f405a7)。下图描述了Databinding数据流向:

>>>>

3、MVVM-DataBinding框架简介

谷歌提供了一个Databinding工具,为什么我们要重新定义一套框架呢?其实在我们使用Databinding的过程中可以发现,单纯的使用Databinding使用有几个痛点:

  1. Databinding规则比较多,而且每个人对其理解不同,用起来比较杂乱,导致代码阅读性差;
  2. 对于已经使用MVP框架的开发者来说,希望进化到MVVM更顺滑,那要是能把Presenter改成ViewModel就能完成转化简直太开心了。
  3. 实现Databinding数据和UI绑定的方法(如使用DatabindingUtil)较为机械且繁琐。如今并没有一个好的框架能规避以上问题,于是我将DataBinding工具和MVVM框架进行了封装,希望能解决以上问题并融合两者的优点,最终达到1+1>2的效果,下面将讲述是如何做到的。库代码可以移步我的github地址(https://github.com/ganlinux/JDMvvmDatabinding.git)。

>>>>

二、 MVVM-Databinding框架详解

下面我将通过三部分介绍我的MVVM-Databinding框架:

  1. 如何使用本框架
  2. 本框架的实现过程
  3. 本框架的优点及可能的隐患

>>>>

1、如何使用本框架

通常我们开发过程中会在Activity、Fragment、楼层、列表item中使用UI控件,所以我们的框架也将支持这几种情况的数据绑定。俗话说“无规矩不成方圆”,我们通过定义少量规则来避免使用Databinding中的大量规则,进而提高代码可读性。

以下是我们约定的五点规则:

① 我们约定把Activity、Fragment绑定的数据放在xxxViewModel中,楼层绑定的数据放在楼层类(代码中的xxxFloor)中,列表item绑定的数据放在ViewHolder中。就是说要绑定的数据都会放在其处理逻辑的类中。

② Activity和Fragment的布局文件要做些改变,要绑定的数据类名称(如xxxViewModel)使用"viewModel",其类型为要绑定数据的全路径类名。如下图示例:

③ 楼层的布局文件中引用的数据类使用名称为"floor",类型也是要绑定数据的全路径类名,如下图示例:

④ 列表的item布局文件中引用的数据类使用名称为"item",其类型也是要绑定数据的全路径类名。如下图示例:

⑤ 数据的控制逻辑尽量写在处理逻辑的类中,不要写在布局文件中,写在布局文件中会给排查问题造成困难并且造成他人阅读代码困难。

以上是本框架制定的简单规则,剩下的工作基本上跟接入MVP框架相似,与MVP不同的就是我们会修改相应的布局文件达到UI和数据绑定的目的。以下是接入框架的步骤:

1.创建ViewModel/楼层/ViewHolder继承自BaseViewModel/BaseFloorView/BindingViewHolder,里面可以创建要绑定的数据,例如下图:

2. 创建layout文件,按照之前的规则配置要绑定的数据。如指定生成的绑定类名为“DemoNormalFragmentBinding”,名称为"viewModel",其类型为第一步的ViewModel的全路径,绑定布局和控件例如“android:text="@{viewModel.pageTitle}"”,如图:

3.创建Activity、Fragment并继承BaseBindingMvvmActivity或BaseBindingMvvmFragment,继承时需要指定绑定的ViewModel类和Binding类,这一步就完成了数据和布局UI的绑定。楼层和列表item需要完成的是ViewHolder中数据和布局UI的绑定。例如:

完成了上面这三步,就已经完成了布局和数据的绑定,你需要做的就只是写数据变化的逻辑了,只要数据改变对应的UI就会改变了。

是不是很神奇?比MVP更简洁吧?

>>>>

2、本框架的实现过程

先来看下框架的代码结构,如图:

代码一共分四部分:第一部分为公共的ViewBindingAdapter,主要功能是实现公共自定义控件的绑定注入;第二部分为Activity、Fragment、Viewmodel相关基类;第三部分为楼层相关基类;第四部分为Recyclerview列表相关基类。

这里以楼层框架为例,进行相关实现机制的讲解:

1.创建布局文件,生成BR文件占位资源。BR文件是Databinding编译期间生成的,跟R文件类似,主要作用是当数据改变后,可以用该标识符通知 DataBinding,用新的数据去更新UI。这里占位的目的是在SDK中生成一个通用的名称,在其他引用SDK的项目中引用。

2.实现绑定Binding类并设置数据,就是这个步骤省去了开发者手动设置绑定的工作。其实就是调用了Databinding的通用绑定方法,这样就不用开发者显示的调用这个方法了。

3. 由于楼层就是一个Recyclerview的列表组成的,可以继承基类Adapter ,在onBindViewHolder调用show方法,并且调用excutePendingBindings()方法触发刷新。

以上是我楼层实现MVVM-Databinding框架的过程,如果不关心实现过程的开发者可以直接看下demo就可以上手了。下图是楼层demo的实现效果:

>>>>

3、本框架的优点及可能的隐患

这个框架大部分优点其实是结合了MVVM和Databinding的优点,如:

1. 减少findViewbyId造成的IO操作性能损耗,这是Databinding的一条优点,因为Databinding在编译期间就将控件从布局映射到在Binding类中,只是在绑定阶段一次性实例化这些控件就直接可以使用,省去了findViewbyId的IO操作。

2. 减少频繁线程切换,这条也是由Databinding的优点,你可以在任何你想要的线程上进行更新,因为Databinding是在UI线程进行响应。

3. 减少逻辑代码冗余、提高编码效率,这条优点就是本框架的优势所在,也是为什么要将这两种优秀框架集合在一块的原因。

4. 削减DataBinding的混乱规则,这是单纯的使用DataBinding体验较差的地方,在我们的框架里可以摒弃其复杂的规则。

5. 更简单的单元测试,这是MVVM框架的优点,由于其天然的低耦合性,可以使我们单元测试更简单。

可能的隐患

1.由于DataBinding在xml提供了丰富的操作符,但是由于Android studio天生的xml语法检查的贫弱,xml布局中的表达式逻辑错误,不能准确定位,导致debug难度增加,事实上一些BindingAdapter的错误在build的时候也会被提示xml错误。我在开发过程中遇到过几次,常常需要重启Android studio才能消除问题,这个问题只能寄希望于谷歌在其IDE上解决。

2.由于DataBinding是在预编译时期生成一些布局和代码,这可能导致许多需要动态加载资源或代码的工程(比如插件化工程)需要做些改变。当然普通的APP开发使用这个框架是没问题的。

当然如果你按照以上步骤改造了自己的APP,可能过程中还会遇到一个问题,就是ViewModel中上下文引用的问题,当然如果能用应用级别的context当然最好,但是有时候我们必须用activity的context时可能就有些困难了,因为我们不推荐ViewModel持有context,这样做可能造成内存泄漏,这时候我们可以结合Android Architecture Components来实现context的获取,在我的github的工程中有两个分支,其中mvvm-databinding-aac分支就是结合了Android Architecture Components来实现的。

>>>>

三、 结语

数据绑定的应用软件开发是一种趋势,使用DataBinding的优点显而易见。在我们选择框架的过程中需要考虑诸多问题,比如性能问题、使用便捷程度、单元测试、是否相互独立等。

当然还有一点很重要的就是,共同开发的同事是否认同并喜欢这种开发方式,毕竟这会影响到他们的开发流程,习惯和体验。如何说服他们认可这种框架,就需要你提供便捷和健壮的封装框架,使他们很爽很开心很便捷地使用这种框架,并且能够满足项目代码的可扩展性,解耦和相关独立。做到这些,就能满足调用者,项目代码健壮性,模块独立性和可扩展性的需要了。

我以上讲述算是抛转引玉吧,希望能共同完善框架,共同进步。

github地址:

https://github.com/ganlinux/JDMvvmDatabinding.git

---------------------END---------------------

本文分享自微信公众号 - 京东技术(jingdongjishu)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-07-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 未来架构:从服务化到云原生 | 每月一书(第5期)

    互联网架构不断演化,经历了从集中式架构到分布式架构,再到云原生架构的过程。云原生因能解决传统应用升级缓慢、架构臃肿、无法快速迭代等问题而成了未来云端应用的目标。

    京东技术
  • 编程语言那么多,到底哪款适合你?

    京东技术
  • Apache ShardingSphere开源分布式数据库中间件应用详解

    相比于数据分片方案的逐渐成熟,集性能、透明化、自动化、强一致、并能适用于各种应用场景于一体的分布式事务解决方案则显得凤毛麟角。基于两或三阶段提交的分布式事务的性...

    京东技术
  • Java程序员拼多多3轮面试,你撑得住几轮?

    面试一直是大家关注的问题,包括最近有很多人跟我讲投了很多简历出去,就像泥牛入海一样了无音讯了,确实出于程序员的直觉,今年是要比往年要更冷一些。

    本人秃顶程序员
  • Java程序员拼多多3轮面试,你撑得住几轮?

    面试一直是大家关注的问题,包括最近有很多人跟我讲投了很多简历出去,就像泥牛入海一样了无音讯了,确实出于程序员的直觉,今年是要比往年要更冷一些。

    本人秃顶程序员
  • 面试中的路由问题

    路由最初是出现在后端中,后端根据不同的路由返回不同的页面,后来随着单页面应用(SPA)诞生,前端也出现了路由,实现了不用刷新页面就可以更新页面的效果。

    不作声
  • 论文解读——Path tracking of wheeled mobile robots based on dynamic…

    《Path tracking of wheeled mobile robots based on dynamic prediction model》是期刊《IE...

    路径跟踪快讯
  • Python 基础元素

    JNingWei
  • FBKVOController源码剖析与学习

    建议查看原文:https://www.jianshu.com/p/4a3f9fe13e5a(不定时更新)

    Dwyane
  • Android异步消息处理机制完全解析,带你从源码的角度彻底理解

    之前也是由于周末通宵看TI3比赛,一直没找到时间写博客,导致已经有好久没更新了。惭愧!后面还会恢复进度,尽量保证每周都写吧。这里也是先恭喜一下来自瑞典的Alli...

    用户1158055

扫码关注云+社区

领取腾讯云代金券