android MVVM框架学习总结(三)

1. 为什么需要在项目中引入架构或者框架

使用架构的目的是使程序模块化,做到模块内部的高聚合和模块之间的低耦合,使得程序在开发的过程中,开发人员只需要专注于一点,提高程序开发的效率,而且最重要的一点,架构和模式并不是说让你的代码量更少了,往往可能还会增大,但是它帮你在逻辑上更简单的了,很好的定义了单一原则,提供了更好的扩展性,方便定位问题以及后续需求变更时不至于满篇的去改一大堆东西。对于不同量级的工程,具体架构的实现方式必然是不同的,切忌为了设计而设计,为了架构而架构,试想想,如果你的项目只有几个Java文件来做业务逻辑,还要什么架构,撸起袖子就是写,只需要做好模块和层次的划分就可以了。

2. 当前有哪些架构或者框架可以使用

软件技术发展的过程也是软件设计架构发展的过程,无论框架如何变化,目的都只有一个,降低视图层与业务层的耦合度,最大限度的提高组件的复用率,软件架构在Android技术上进化过程如下:MVC》MVP》MVVM。

2.1 MVC

这里写图片描述
视图层(View)
对应于xml布局文件,

控制层(Controller)
Android的控制层是由Activity来承担的,Activity本来主要是作为初始化页面,展示数据的操作,但是因为XML视图功能太弱,所以Activity既要负责视图的显示又要加入控制逻辑,承担的功能过多,在复杂一点的页面Activity代码量达到1000+也就不足为奇了。

模型层(Model)
我们针对业务模型,建立的数据结构和相关的类,它主要负责网络请求,数据库处理,I/O的操作。

优点:优点是对于混乱的软件组织方式有了一个明确的组织方式,通过Control来掌控全局,同时将View展示和Model的变化分离开。

缺点:从图示中也可以看出,在View和Model之间是直接进行交互的,也就是说View和Model之间是可以相互产生影响的,这样在代码中就必然会导致View和Model之间的耦合。

2.2 MVP

这里写图片描述
在Android开发中,Activity并不是一个标准的MVC模式中的Controller,本来它的首要职责是加载应用的布局和初始化用户界面,接受并处理来自用户的操作请求,进而作出响应。在MVC模式下随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。

视图层(View)
负责绘制UI元素、与用户进行交互,对应于xml、Activity、Fragment、Adapter

模型层(Model)
负责存储、检索、操纵数据,一般包含网络请求,数据库处理,I/O流。

控制层(Presenter)
Presenter是整个MVP体系的控制中心,作为View与Model交互的中间纽带,处理View于Model间的交互和业务逻辑。

它的具体实现就是接收到View的请求,从Model层获取数据,将数据进行处理,通过View层的接口回调给Activity或者Fragment。MVP能够让Activity成为真正的View,只做UI相关的事。
优点如下:
1、模型与视图完全分离,我们可以修改视图而不影响模型;
2、项目代码结构(文件夹)清晰,一看就知道什么类干什么事情;
3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁
4、协同工作(例如在设计师没出图之前可以先写一些业务逻辑代码或者其他人接手代码改起来比较容易)
缺点如下:
1、Presente层与View层是通过接口进行交互的,View层可能会有大量的接口,因为有可能好几个Activity都是去实现同一个View接口,那么所有用到的Activity都要去实现所有的方法(不管你是否用到),而且如果后面有些方法要删改,Presenter和Activity都要改动,比较麻烦;
2、MVP把Activity相当的一部分责任放到了Presenter来处理,复杂的业务同时也可能会导致P层太大,一旦业务逻辑越来越多,View定义的方法越来越多,会造成Activity和Fragment实现的方法越来越多,依然臃肿。

2.3 MVVM

这里写图片描述
基于MVP缺点的暴露,google进一步退出了MVVM的架构。
MVVM模式不是四层,任然是3层,分别是Model、View、ViewModel

Model :负责数据实现和逻辑处理,类似MVP。
View : 对应于Activity和XML,负责View的绘制以及与用户交互,类似MVP。
ViewModel : 创建关联,将model和view绑定起来,如此之后,我们model的更改,通过viewmodel反馈给view,从而自动刷新界面。

通常情况下,数据的流向是单方面的,只能从代码流向UI,也就是单向绑定;而双向绑定的数据流向是双向的,当业务代码中的数据改变时,UI上的数据能够得到刷新;当用户通过UI交互编辑了数据时,数据的变化也能自动的更新到业务代码中的数据上。而DataBinding是一个实现数据和UI绑定的框架,是构建MVVM模式的一个关键的工具,它是支持双向绑定的。
优点:可以使得数据流的走向更加的清晰明了,同时也简化了开发,数据和视图只需要进行一次绑定即可。
缺点:1. 目前这种架构方式的实现方式比较不完善规范,常见的就是DataBinding框架。2.大量注解生成的代码,调试起来不太方便。

这里写图片描述

2.4 MVVM架构在Android上的架构实现

下面是MVVM的Android实现架构图

这里写图片描述

从上面的实现图,我们具体说下它的工作原理

  • Model
    Model层即Repository就是职责数据的存储、读取网络数据、操作数据库数据以及I/O,一般会有一个ViewModel对象来调用获取这一部分的数据。
  • View
    即为Activity/Fragment, 这里的View才是真正的View,为什么这么说?View层做的仅仅和UI相关的工作,我们只在XML、Activity、Fragment写View层的代码,View层不做和业务相关的事,也就是我们的Activity 不写和业务逻辑相关代码,一般Activity不写更新UI的代码,如果非得要写,那更新的UI必须和业务逻辑和数据是没有关系的,只是单纯UI逻辑来更新UI,比如:滑动时头部颜色渐变、editttext根据输入内容显示隐藏等,简单的说:View层不做任何业务逻辑、不涉及操作数据、不处理数据、UI和数据严格的分开。
  • ViewModel
    ViewModel 只做和业务逻辑和业务数据相关的事,不做任何和UI、控件相关的事,ViewModel 层不会持有任何控件的引用,更不会在ViewModel中通过UI控件的引用去做更新UI的事情。ViewModel就是专注于业务的逻辑处理,操作的也都是对数据进行操作,这些个数据源绑定在相应的控件上会自动去更改UI,开发者不需要关心更新UI的事情。

3. DataBinding框架介绍及使用

3.1 DataBinding简介

早在2015谷歌 I/O大会上,就介绍了一个新的框架DataBinding,从名字就可以看出来,这是一个数据绑定框架。我们为什么要使用DataBinding?
1. 再也不需要编写findViewById了,有人会说,已经有butterknife了,很好用。
2. 更新UI数据需切换至UI线程,也有人说,有rxjava了。
但是DataBinding,不仅仅能解决这2个问题,它的核心优势在于,它解决了将数据分解映射到各个view的问题。具体来说,就是针对每个Activity或者Fragment的布局,在编译阶段,会生成一个ViewDataBinding类的对象,该对象持有Activity要展示的数据和布局中的各个view的引用。同时还有如下优势:将数据分解到各个view、在UI线程上更新数据、监控数据的变化,实时更新,这样一来,你要展示的数据已经和展示它的布局紧紧绑定在了一起。
Databinding源码路径

android/frameworks/data-binding$ tree -L 1
.
├── Android.mk
├── baseLibrary
├── build.gradle
├── CleanSpec.mk
├── compilationTests
├── compiler
├── compilerCommon
├── databinding.properties
├── developmentPlugins
├── extensions
├── gradle
├── gradlePlugin
├── gradle.properties
├── gradlew
├── integration-tests
├── library
├── localize.sh
├── plugins-repo
├── prebuilds
├── propLoader.gradle
├── samples
└── settings.gradle

3.2 构建环境

Gradle配置
使用gradle插件1.5-alpha1以上

 android{       
  ......  
    dataBinding {
        enabled = true
    }
  ......
}

Android.mk配置

Android 6.0 的 .mk编译系统对databinding的支持目前比较有限,暂不支持.mk编译,在Android 7.0中JACK编译器已经对annotation Process有比较完善的支持
Android 7.0编译系统对DATA_BINDING相关的支持
配置代码如下:

Android.mk文件中配置

LOCAL_DATA_BINDING := true

Android 7.0编译系统对data-binding框架支持代码如下:
代码路径/build/core/package_internal.mk

ifeq ($(LOCAL_DATA_BINDING),true)
data_binding_intermediates := $(intermediates.COMMON)/data-binding
LOCAL_JAVACFLAGS += -processorpath $(DATA_BINDING_COMPILER) -s $(data_binding_intermediates)/anno-src
LOCAL_JACK_FLAGS += --processorpath $(DATA_BINDING_COMPILER)

LOCAL_STATIC_JAVA_LIBRARIES += databinding-baselibrary
LOCAL_STATIC_JAVA_AAR_LIBRARIES += databinding-library databinding-adapters

data_binding_res_in := $(LOCAL_RESOURCE_DIR)
data_binding_res_out := $(data_binding_intermediates)/res

# Replace with the processed merged res dir.
LOCAL_RESOURCE_DIR := $(data_binding_res_out)

LOCAL_AAPT_FLAGS += --auto-add-overlay --extra-packages com.android.databinding.library
endif  # LOCAL_DATA_BINDING
ifeq ($(LOCAL_DATA_BINDING),true)
data_binding_stamp := $(data_binding_intermediates)/data-binding.stamp
$(data_binding_stamp): PRIVATE_INTERMEDIATES := $(data_binding_intermediates)
$(data_binding_stamp): PRIVATE_MANIFEST := $(full_android_manifest)
# Generate code into $(LOCAL_INTERMEDIATE_SOURCE_DIR) so that the generated .java files
# will be automatically picked up by function compile-java.
$(data_binding_stamp): PRIVATE_SRC_OUT := $(LOCAL_INTERMEDIATE_SOURCE_DIR)/data-binding
$(data_binding_stamp): PRIVATE_XML_OUT := $(data_binding_intermediates)/xml
$(data_binding_stamp): PRIVATE_RES_OUT := $(data_binding_res_out)
$(data_binding_stamp): PRIVATE_RES_IN := $(data_binding_res_in)
$(data_binding_stamp): PRIVATE_ANNO_SRC_DIR := $(data_binding_intermediates)/anno-src

$(data_binding_stamp) : $(all_res_assets) $(full_android_manifest) \
    $(DATA_BINDING_COMPILER)
    @echo "Data-binding process: $@"
    @rm -rf $(PRIVATE_INTERMEDIATES) $(PRIVATE_SRC_OUT) && \
      mkdir -p $(PRIVATE_INTERMEDIATES) $(PRIVATE_SRC_OUT) \
          $(PRIVATE_XML_OUT) $(PRIVATE_RES_OUT) $(PRIVATE_ANNO_SRC_DIR)
    $(hide) java -classpath $(DATA_BINDING_COMPILER) android.databinding.tool.MakeCopy \
      $(PRIVATE_MANIFEST) $(PRIVATE_SRC_OUT) $(PRIVATE_XML_OUT) $(PRIVATE_RES_OUT) $(PRIVATE_RES_IN)
    $(hide) touch $@

# Make sure the data-binding process happens before javac and generation of R.java.
$(R_file_stamp) $(full_classes_compiled_jar) : $(data_binding_stamp)
# The dependency path when jack is enabled
$(built_dex_intermediate) : $(data_binding_stamp)
endif  # LOCAL_DATA_BINDING

3.3 DataBinding使用

猜你喜欢

转载自blog.csdn.net/u011897062/article/details/79771277