Android技术栈(四)Android-Jetpack-MVVM-完全实践

本文包含AndroidMVVM体系中的很多部分,主要对ViewModel+DataBinding+RxJava+LiveData+Lifecycle等笔者所使用的技术体系进行解析.

本文字数较多,内容较为完整并且后续还会追加更新,阅读本篇文章需要较长时间,建议读者分段阅读.

所有文字均为个人学习总结和理解,仅供参考,如有纰漏还请指出,笔者不胜感激.

1.1 配置环境

  • 笔者的Android Studio版本=3.2
  • Jetpack最低兼容到Android=2.1,API=7

1.2 为什么要选择MVVM?

为什么要选择MVVM?要回答这个问题首先就要介绍MVCMVP这两种模式,从MVCMVVM其实大家想的都是怎么把ModelView尽可能的拆开(熟悉三者定义的朋友可以跳过该节).

1.2.1 MVC

MVCModel-View-Controller)即传统Android开发中最常用的模式:

  • 通常使用Activity/Fragment作为Controller层,
  • android.view.View的子类以xml构建文件构建起的布局作为View
  • SQLite数据库,网络请求作为Model层.

但由于Activity/Fragment的功能过于强大并且实际上包含了部分View层功能,导致最后Activity/Fragment既承担了View的责任,又承担了Controller的责任.所以一般较复杂的页面,Activity/Fragment很容易堆积代码,最终导致Controller混杂了View层和业务逻辑(也就是你们所知道的一个Activity三千行)

MVCView层与Model几乎几乎完全没有隔离,View层可以直接操作Model层,Model层的回调里也可能会直接给View赋值.Controller的概念被弱化,最后只剩下MV没有C了.

这也将导致但你想把某个界面上的元素进行更新时,他会牵扯到一堆跟Model层相关的代码,这个问题在你变更Model层的时候同样也会出现,这个问题其实是没有很好的将逻辑分层导致的.

1.2.2 MVP

MVPModel-View-Presenter)架构设计,是当下最流行的开发模式,目前主要以Google推出的TodoMVP为主,MVP不是一种框架,它实际上更类似一种分层思想,一种接口约定,具体体现在下面:

  • 定义IView接口,并且在接口中约定View层的各种操作,使用android.view.View的子类以xml构建文件构建起的布局Activity/Fragment作为布局控制器,实现IView这个View层的接口,View层的实际实现类保留一个IPresenter接口的实例.
  • 定义IPresenter接口,并且在接口中约定Presenter层的各种操作.可以使用一个与View无关的类实现它,一般是XxxPresenterImpl.通常情况下Presenter层会包含Model层的引用和一个IView接口的引用,但不应该直接或者间接引用Viewandroid.view.View的子类,甚至是操作的参数中也最好不要有android.view.View的子类传进来,因为它应该只负责业务逻辑和数据的处理并通过统一的接口IView传递到View层.
  • 不需要为Model层定义一个IModel的接口,这一层是改造最小的.以前该怎么来现在也差不多该怎么来.但是现在Presenter把它和View隔开了,Presenter就可以作为一段独立的逻辑被复用.

MVP模式解决了MVC中存在的分层问题,Presenter层被突出强调,实际上也就是真正意义上实现了的MVC

但是MVP中其实仍然存在一些问题,比如当业务逻辑变得复杂以后,IPresenterIView层的操作数量可能将会成对的爆炸式增长,新增一个业务逻辑,可能要在两边增加数个通信接口,这种感觉很蠢.

并且,我们要知道一个Presenter是要带一个IView的,当一个Presenter需要被复用时,对应的View就要去实现所有这些操作,但往往一些操作不是必须实现的,这样会留下一堆TODO,很难看.

1.2.3 MVVM

MVVMModel-View-ViewModel)由MVP模式演变而来,它由View层,DataBinding,ViewModel层,Model层构成,是MVP的升级版并由GoogleJetpack工具包提供框架支持:

  • View层包含布局,以及布局生命周期控制器(Activity/Fragment)
  • DataBinding用来实现View层与ViewModel数据的双向绑定(但实际上在Android JetpackDataBinding只存在于布局和布局生命周期控制器之间,当数据变化绑定到布局生命周期控制器时再转发给ViewModel,布局控制器可以持有DataBindingViewModel不应该持有DataBinding)
  • ViewModelPresenter大致相同,都是负责处理数据和实现业务逻辑,但是ViewModel层不应该直接或者间接地持有View层的任何引用,因为一个ViewModel不应该直达自己具体是和哪一个View进行交互的.ViewModel主要的工作就是将Model提供来的数据直接翻译成View层能够直接使用的数据,并将这些数据暴露出去,同时ViewModel也可以发布事件,供View层订阅.
  • Model层与MVP中一致.

MVVM的核心思想是观察者模式,它通过事件和转移View数据持有权来实现View层与ViewModel层的解耦.

MVVMView不是数据的实际持有者,它只负责数据如何呈现以及点击事件的传递,不做的数据处理工作,而数据的处理者和持有者变成ViewModel,它通过接收View层传递过来的时间改变自身状态,发出事件或者改变自己持有的数据触发View的更新.

MVVM解决了MVP中的存在的一些问题,比如它无需定义接口,ViewModelView层彻底无关更好复用,并且有GoogleAndroid Jetpack作为强力后援.

但是MVVM也有自己的缺点,那就是使用MVVM的情况下ViewModelView层的通信变得更加困难了,所以在一些极其简单的页面中请酌情使用,否则就会有一种脱裤子放屁的感觉,在使用MVP这个道理也依然适用.

2 DataBinding

2.1 坑

要用一个框架那么就要先说它的点.那就是不建议在使用DataBinding的模块同时使用apply plugin: 'kotlin-kapt'.

因为现在kapt还有很多Bug,使用kapt时,在WindowsDataBinding格式下的xml中如果包含有中文,会报UTF-8相关的错误.

笔者一开始猜想这是由于JVM启动参数没有设置成-Dfile.encoding=UTF-8导致的,在gradle.properties中改过了,无果,Stack Overflow搜过了,没找到,如果有大佬知道怎么解决,还请指点一二

如果你在模块中同时使用kotlinDataBinding是可以的,但是请一定不要使用kapt,除非JB那帮大佬搞定这些奇怪的问题.

这就意味这你所有的kotlin代码都不能依赖注解处理器来为你的代码提供附加功能,但是你可以把这些代码换成等价的Java实现,它们可以工作得很好.

2.2 DataBinding的兼容性

先说一点,DataBinding风格的xml会有"奇怪"的东西入侵Android原生的xml格式,这种格式LayoutInfalter是无法理解,但是,当你对这些奇怪的xml使用LayoutInfalter#inflate时亦不会报错,并且布局也正常加载了,这是为什么呢?

这是因为在打包时,Gradle通过APT把你的DataBinding风格的xml全部翻译了一遍,让LayoutInfalter能读懂他们,正是因为这个兼容的实现,而使得我们可以在使用和不使用DataBinding间自由的切换.

2.3 DataBinding风格的XML

要想使用DataBinding,先在模块的build.gradle中添加

android{
//省略…
dataBinding {
enabled = true
}
}

来启用DataBinding支持.

DataBinding不需要额外的类库支持,它被附加在你的android插件中,它的版本号与你的android插件版本一致.

classpath ‘com.android.tools.build:gradle:3.3.2’

DataBinding风格的xml中,最外层必须是layout标签,并且不支持merge标签,编写xml就像下面这样







2.3.1 变量领域

data标签包裹的是变量领域,在这里你可以使用variable定义这个布局所要绑定的变量类型,使用name来指定变量名,然后用type来指定其类型.

如果一些类型比较长,而且由需要经常使用你可以像Java一样使用import导入他们(java.lang.*会被默认导入),然后就不用写出完全限定名了,就像这样


有必要时(比如名字冲突),你还可以用Action为一个类型指定一个别名,这样你就能在下文中使用这个别名.

2.3.

你可能感兴趣的:(作者\/,android,android,jetpack)