mvvm模式
Posted awodefengduanwu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mvvm模式相关的知识,希望对你有一定的参考价值。
一、前言
MVP 中我们说过随着业务逻辑的增加,UI 的改变多的情况下,会有非常多的跟 UI 相关的 case,这样就会造成 View 的接口会很庞大。而 MVVM 就解决了这个问题,通过双向绑定的机制实现数据和 UI 内容,只要想改其中一方,另一方都能够及时更新的一种设计理念,这样就省去了在 View 层中写很多 case 的情况,只需要改变数据就行。
二、MVVM详解
-
2.1、MVVM 设计图:
一般情况下就这两种情况,这看起来跟 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 放在哪里?