mvvm模式

Posted awodefengduanwu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mvvm模式相关的知识,希望对你有一定的参考价值。

一、前言

MVP 中我们说过随着业务逻辑的增加,UI 的改变多的情况下,会有非常多的跟 UI 相关的 case,这样就会造成 View 的接口会很庞大。而 MVVM 就解决了这个问题,通过双向绑定的机制实现数据和 UI 内容,只要想改其中一方,另一方都能够及时更新的一种设计理念,这样就省去了在 View 层中写很多 case 的情况,只需要改变数据就行。

二、MVVM详解

  • 2.1、MVVM 设计图:

    img

一般情况下就这两种情况,这看起来跟 MVP 好像没啥差别,其实区别还是挺大的。在 MVP 中 View 和 presenter 要相互持有方便调用对方,而在 MVP 中 View 和 ViewModel 通过 Binding 进行关联,他们之前的关联处理通过 DataBinding 完成。

  • 2.2、MVVM 与 DataBinding 的关系

一句话表述就是,MVVM 是一种思想,DataBinding 是谷歌推出的方便实现 MVVM 的工具。在 google 推出 DataBinding 之前,因为xml layout功能较弱,想实现 MVVM 非常困难,而 DataBinding 的出现可以让我们很方便的实现 MVVM。

  • 2.3、DataBinding 简介

DataBinding 是实现视图和数据双向绑定的工具,这里简单介绍下基本用法,详细用法可以参照官方:https://developer.android.com/topic/libraries/data-binding/ 启用DataBinding,只需要在 gradle 文件中添加如下代码:

android {    
    dataBinding{
        enabled true
    }
}

通过 DataBindingUtil 可以动态生成一个 ViewDataBinding 的子类,类名以 layout 文件名大写加 Binding 组成,如:

ActivitySampleMvvmBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sample_mvvm);

在 layout 中需要我们配置每个控件绑定的实体对象,以 layout 进行包裹,data 中配置变量名和类型,通过 @{} 或 @={} 的方式进行引用,其中 @={} 的方式表示双向绑定。

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
    <data >
        <variable
            name="user"
            type="com.androfarmer.mvvm.model.SampleModel.UserInfo">
        </variable>
    </data>
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
 
    <TextView
        android:id="@+id/tv_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@={user.name}"/>
    <TextView
        android:id="@+id/tv_age"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@={user.age+``}"/>
 
</LinearLayout>
</layout>

以上为具体在 xml 的用法展示

public static class UserInfo  extends BaseObservable
    {
        private int age;
        private String name;
 
        @Bindable
        public int getAge() {
            return age;
        }
 
        public void setAge(int age) {
            this.age = age;
            notifyPropertyChanged(BR.age);
        }
 
        @Bindable
        public String getName() {
            return name;
        }
 
        public void setName(String name) {
            this.name = name;
            notifyPropertyChanged(BR.name);
        }
    }

为了实现双向绑定还需要对数据实体类做处理,继承 BaseObservable,对读写方法做 @Bindable 和 notifyPropertyChanged 处理。还可以直接使用官方提供的泛型可观察对象 ObservableField,比如: private ObservableField name=new ObservableField<>();

  • 2.4、MVVM Sample

MVVM 跟 MVP 一样,将三层划分的很清楚,Activity 和 xml layout 充当 View,ViewModel 处理业务逻辑以及获取数据,弱化 Model。 很多代码跟前面类似,这里只列出核心代码,ViewModel 层的:

public interface BaseViewModel {
    void onDestroy();
}
 
public abstract class AbstractViewModel<T extends ViewDataBinding> implements BaseViewModel {
    public T mViewDataBinding;
    public AbstractViewModel(T viewDataBinding)
    {
        this.mViewDataBinding=viewDataBinding;
    }
 
    @Override
    public void onDestroy() {
        mViewDataBinding.unbind();
    }
}
 
public class SampleViewModel extends AbstractViewModel<ActivitySampleMvvmBinding> {
 
    public SampleViewModel(ActivitySampleMvvmBinding viewDataBinding) {
        super(viewDataBinding);
    }
 
    public  void getUserInfo(String uid, Callback1<SampleModel.UserInfo> callback)
    {
        //从网络或缓存获取信息
        SampleModel.UserInfo userInfo=new SampleModel.UserInfo();
        userInfo.setName("tom");
        userInfo.setAge(18);
        callback.onCallBack(userInfo);
    }
}

ViewMode 层主要处理业务逻辑和获取数据,mViewDataBinding 是通过 View 层传递过来。

 private SampleViewModel mSampleViewModel;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivitySampleMvvmBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sample_mvvm);
        mSampleViewModel=new SampleViewModel(binding);
        setDataToView();
    }
    private void setDataToView()
    {
        mSampleViewModel.getUserInfo("uid", new Callback1<SampleModel.UserInfo>() {
            @Override
            public void onCallBack(SampleModel.UserInfo userInfo) {
                mSampleViewModel.mViewDataBinding.setUser(userInfo);
            }
        });
    }

xml layout 代码在上面介绍 databing 的用法时已给出,通过上面代码我们就将数据 UserInfo 跟 View 进行绑定了。比如我们更新用户信息,可以直接对 View 上的属性进行修改: mSampleViewModel.mViewDataBinding.tvName.setText(“rose”); 也可以通过修改 UserInfo 实体类的字段信息: mSampleViewModel.mViewDataBinding.setUser(userInfo);

从此告别 MVP 中 View 层好多接口的问题,让 View 变得更简洁,修改任何一方,两者都会保持数据同步。

  • 2.5、MVVM 总结

看起来 MVVM 很好的解决了 MVC 和 MVP 的不足,但是由于数据和视图的双向绑定,导致出现问题时不太好定位来源,有可能数据问题导致,也有可能业务逻辑中对视图属性的修改导致。如果项目中打算用 MVVM 的话可以考虑使用官方的架构组件 ViewModel、LiveData、DataBinding 去实现 MVVM。

三、关于 MVC、MVP、MVVM 如何选择的探讨

前面在介绍 MVC、MVP、MVVM 时并没有去详细列出他们的优缺点,主要原因有两个:

网上这方面总结的还是挺多的;
其实关于架构、设计、模块化等等,它们的优缺点没有绝对的,主要看实现者如何去做。

比如在 mvp 中我们要实现根据业务逻辑和页面逻辑做很多 Present 和 View 的具体实现,如果这些 case 太多,会导致代码的可读性变差。但是通过引入 contract 契约类,会让业务逻辑变得清晰许多。因此不管是用哪种设计模式,只要运用得当,都可以达到想要的结果。 如果非要说怎么选的话,以我浅薄的知识建议如下:

如果项目简单,没什么复杂性,未来改动也不大的话,那就不要用设计模式或者架构方法,只需要将每个模块封装好,方便调用即可,不要为了使用设计模式或架构方法而使用。
对于偏向展示型的 app,绝大多数业务逻辑都在后端,app 主要功能就是展示数据,交互等,建议使用 mvvm。
对于工具类或者需要写很多业务逻辑 app,使用 mvp 或者 mvvm 都可。
如果想通过一个项目去学习架构和设计模式,建议用MVC然后在此基础上慢慢挖掘改进。最后你可能发现,改进的最终结果可能就变成了 mvp,mvvm。

以上是关于mvvm模式的主要内容,如果未能解决你的问题,请参考以下文章

Android MVVM:具有多个片段的活动 - 将共享 LiveData 放在哪里?

WPF MVVM从入门到精通1:MVVM模式简介

Android MVVM在哪里存储数据?

为啥要避免 WPF MVVM 模式中的代码隐藏?

MVVM Light:在 XAML 中添加 EventToCommand 而不使用 Blend、更简单的方法或片段?

1.1 vue里面的mvvm模式是什么?