MVP、MVVM(未完)

MVP、MVVM(未完)

2018, Jul 14    

MVP模式

mvp模式(model, view, presenter)主要是解决MVC模式中,M和V的交互。基本结构如下,view表示界面,负责和用户的交互,在有交互事件时,通过presenter来实现相关的业务逻辑。Presenter负责更新model层,并且在model发生变化时,同步给view,而不是由model直接同步给view。
(按照对mvc、mvp和面向对象的理解,觉得目前项目中的代码可能连mvc都不算,没有实现v和m或者c和m的划分,model虽然表示数据层,但从面向对象的思想来说,model也是一个对象,对象应该是包括属性和行为的,只包含属性以及getter、setter的对象应该再去考量是不是设计有问题(当前数据定义没有什么可改的,应该是controller中的逻辑太多)。所以,数据相关的行为应该放在数据层,很多时候,这些相关逻辑都放在了v或者c中,有时候复杂数据逻辑抽离在utils类,但是调用仍然是在controller中)
image

image model: TaskReposiry,定义了很多task的创建、更新、获取等接口,整个app内公用的数据模型。在Injection类中获取,TaskRepository持有远程数据源 (FakeTasksRemoteDataSource),和本地数据源(TasksLocalDataSource)的实例,三者都是单例模式,继承TasksDataSource接口,提供数据以及相关操作功能。
view:AddEditTaskFragment,持有界面中的字view,继承自AddEditTaskContract.View,对外提供界面相关的操作接口,比如showTaskList, setTitle等。持有presenter,当界面需要显示或保存数据时,借助presenter操作datarepository。
presenter: AddEditTaskPresenter, 持有view和数据model,数据的获取和存放,都通过presenter,获取和存放的逻辑以及关联的操作逻辑(比如保存之后要显示列表)都在presenter中,view只提供简单的展示和切换逻辑。 image 隔离了view和数据,解耦了数据反向对view的通知,数据变化对view的操作,通过presenter调用view对外的接口进行。与mvc的区别就是,类似controller角色的presenter可以反作用于view。mvc中controller像是为view服务的,view持有controller,触发controller去操作,而presenter也可以对view的接口进行操作。这样的好处是,view不依赖于model,所以数据如何定义获取操作view不关心,可以专注于于用户的交互,因此可以实现复用。在实例的架构中,presenter、view的相互持有都是持有接口的,所以替换presenter的实例和view的实例都很方法,因此都是很方便复用的。
问题:跟activity,fragment的生命周期相关的逻辑;复用的可能性?会出现大量的presenter,presenter之间的交互需要考虑路由机制等;划分逻辑块?有很多功能应该数据更新很少,presenter来解耦model和data的意义似乎不大,但是presenter划分view和逻辑块的想法可以考虑。 缺点:(https://www.jianshu.com/p/4abbff527e75)

  1. Presente层与View层是通过接口进行交互的,接口粒度不好控制。粒度太小,就会存在大量接口的情况,使代码太过碎版化;粒度太大,解耦效果不好。因为View定义的方法并不一定全部要用到,可能只是后面要用到先定义出来(后面要不要删也未知),而且如果后面有些方法要删改,Presenter和Activity都要删改,比较麻烦;
    2.V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身。如果这一层也能解耦就更好了。
    3.复杂的业务同时也可能会导致P层太大,代码臃肿的问题依然不能解决,这已经不是接口粒度把控的问题了,一旦业务逻辑越来越多,View定义的方法越来越多,会造成Activity和Fragment实现的方法越来越多,依然臃肿。
    优点:测试的便利性, view的复用,逻辑更清楚。(前两者目前似乎都用不上,测试方法工程还是主要靠人工和自动化测试组去测试;view如果要复用划分的需要特别细,没有想到可以直接复用的大量逻辑)

MVVM

mvvm模式(model,view,viewmodel)。 View和ViewModel间没有了MVP的界面接口,viewmodel中不持有view实现的接口,而是与view中的属性同步的属性,相互绑定实现界面的更新。wiki解释viewmodel是负责从model中转化或者直接取数据,使得这些数据对象能够容易的管理和呈现。从这个角度说,viewmodel更像是一个model而不是view。在view中。便于测试:不需要开发人员手动去编写特殊用例,viewmode和view能够动态的绑定更新。个人理解,viewmodel拆分m和v的方式相当于把自己当做view,通过自身也设置与view相同的属性(只取变动的部分),然后这些属性跟view同步起来,这样就完全可以代表view去做所有的逻辑操作。
image 官方提供了两个案例,mvvm-databinding和 mvvm-live。
mvvm-databinding是利用android的databinding来实现viewmodel和view的属性同步。mvvm-live在binding的基础上增加了livedata组件,新增了SingleLiveEvent类来同步生命周期,viewmodel也继承了android中的viewmodel(AndroidViewModel)来实现。
mvvm-databinding实现基于android的databinding组件。

databinding

(https://www.jianshu.com/p/ba4982be30f8) databinding用来实现界面和数据的绑定。基本配置如下: -build中开启

dataBinding {
   enabled = true
}
  • view的layout文件中layout下增加data属性,这里将view跟AddEditTaskViewModel对象绑定起来,这样在layout中就可以使用AddEditTaskViewModel的成员变量。
<data>
    <variable
        name="viewmodel" 
        type="com.....AddEditTaskViewModel" />
</data>
android:visibility="@{viewmodel.dataLoading ? View.GONE : View.VISIBLE}">
  • 定义数据为观察数据。通过数据扩展BaseObservable类,定义ObseravbleField、ObseravbleCollection等的成员变量实现。
public class AddEditTaskViewModel {
    public final ObservableField<String> title = new ObservableField<>();
    public final ObservableField<String> description = new ObservableField<>();
    ...
    }
    
public class TasksViewModel extends BaseObservable {

    // These observable fields will update Views automatically
    public final ObservableList<Task> items = new ObservableArrayList<>();
    public final ObservableBoolean dataLoading = new ObservableBoolean(false);
	...	
}
  • 绑定数据
    Android studio会根据layout文件自动生成一个默认的Binding类,类名是根据layout文件名去掉_加”Binding”。获取binding类然后通过setViewModel(名称为自己定义的名称)的方式实现。获取binding对象的方式,从代码中找了一下,有以下几种:
mViewDataBinding = AddtaskFragBinding.bind(root);

mViewDataBinding = DataBindingUtil.inflate(
                inflater, R.layout.statistics_frag, container, false);
                
mTasksFragBinding = TasksFragBinding.inflate(inflater, container, false)
  • 事件处理