浅谈Android中的MVVM模式

来源:互联网 发布:外贸邦海关数据有用吗 编辑:程序博客网 时间:2024/06/04 18:16

大家好啊,我是kele。众所周知,Android的设计模式主要有三个:MVC,MVP,MVVM。今天主要来谈一下MVVM模式,简单说明它的好处以及它和MVP在实现方面的区别。

DataBinding

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

提到MVVM就不得不提到Google推出的这款数据绑定(DataBinding)框架,让它加入你的项目中。然后,改变你的布局文件:

<?xml version="1.0" encoding="utf-8"?><layout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools">    <data>        <variable            name="user"            type="com.example.zc.taf.model.User"            />    </data>    <LinearLayout        android:id="@+id/activity_main"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{user.name}" />        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"    </LinearLayout></layout>

因为Databinding的缘故,xml文件不再单单是传统的布局文件了,加入layout和data让xml文件现在更好的扮演好View(视图)的角色了。为什么这么说呢,这里我们就要谈一下MVP中的View了。
用过MVP模式开发的同学想必都知道,MVP是以UI和事件为驱动的传统模型,由于数据经常发生变化,更新UI需要手动调用V层或者P层相关的接口,相对来说缺乏自动性、监听性。而且从某种程度来说,V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身。
用到Databinding就不一样了,双向绑定的概念让传统的布局文件由被动转为主动,数据驱动UI,而且View与ViewModel实现了完美的解耦,这也解决了MVP模式下的缺点。

MVVM

在MVP模式中,我们的Presenter必须知道View的存在,所以当您从Model获取数据时,可以像view.refresh(data)一样调用。但是在MVVM中,我们的中间层ViewModel(不是Presenter)不需要知道View的存在,或者它不关心View。任何人都可以是View,我(ViewModel)应该做的只是发送UI逻辑,任何视图都可以持有它并处理它。

要实现这样的架构,至少有两种方式:
*数据绑定:您应该做的只是更改模型/数据,数据绑定框架将负责将此更改事件发送到视图。
* RxJava:这个解决方案就像Observable模式。 ViewModel只是发送更改事件,他的订阅者将收到通知。顺便说一下,ViewModel不知道,也不需要知道哪个类是接收者。

您要应用MVVM,因此您的代码实际上分为三部分:
* Model:和MVP的M层一样,主要有实体模型/请求数据/处理数据库等
* View: Activity/Fragment/layout xml.
* ViewModel: 负责UI逻辑和数据更改。

让我们根据简单的Demo来看看:

POJO CLASS :

public class User extends BaseObservable {    public String name;    public String userId;    public User(String name,String userId){        this.name = name;        this.userId = userId;    }    @Bindable    public String getName() {        return name;    }    @Bindable    public String getUserId() {        return userId;    }    public void setName(String name) {        this.name = name;        notifyPropertyChanged(BR.name);    }    public void setUserId(String userId) {        this.userId = userId;        notifyPropertyChanged(BR.userId);    }}

我们创建了一个User类,并且其字段的更改由notifyPropertyChanged()发送,其字段的值应通过@Bindable方法获取。

Layout/XML :

<layout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools">    <data>        <variable            name="user"            type="com.example.zc.taf.model.User"            />        <variable            name="handler"   type="com.example.zc.taf.viewmodel.MainActivityViewModel"            />        <import type="android.view.View"/>    </data>    <LinearLayout        android:id="@+id/activity_main"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:orientation="vertical">        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{user.name}" />        <TextView            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:text="@{user.userId}" />        <Button            android:layout_width="300dp"            android:layout_height="wrap_content"            android:onClick="@{handler::btn1Click }"/>        <Button            android:layout_width="300dp"            android:layout_height="wrap_content"            android:onClick="@{()->handler.showToast(user.userId)}"/>        <Button            android:id="@+id/search_btn"            android:layout_width="300dp"            android:layout_height="wrap_content"            />    </LinearLayout></layout>

现在,xml应该有一个称为layout的根元素。而我们的xml包含数据和真实的视图。

ViewModel :

public class MainActivityViewModel implements EventListener {    private ActivityMainBinding binding;    private User user;    private Context context;    public MainActivityViewModel(Context context,ActivityMainBinding binding){        this.binding = binding;        this.context = context;        user = new User("宋小宝","002");        binding.setUser(user);        binding.setHandler(this);     }    public void btn1Click(View v){        user.setName("小沈阳");    }    public void showToast(String note){        Toast.makeText(context,note,Toast.LENGTH_LONG).show();    }    public void setUserId(String userId){        user.setUserId(userId);    }}

ViewModel负责改变POJO类,并且处理view的各种响应事件(点击/选择/滑动等等)

  • 构造函数中的ActivityMainBinding类实际上是由数据绑定生成的类。我们的布局是activity_main.xml,所以生成的类名就是ActivityMainBinding。
  • 如布局xml所示,我们需要两个变量,一个是用户,另一个是处理程序。你必须告诉ActivityMainBinding类的两个实例,所以你必须调用binding.setUser()和binding.setHandler()。
  • btn1Click()和showToast()方法是click 事件方法。
    每当按钮点击时,我们的用户界面也将被刷新。这是数据绑定的好处。

Activity :

public class MainActivity extends AppCompatActivity {    private ActivityMainBinding binding;    private MainActivityViewModel vm;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        binding = DataBindingUtil.setContentView(this,R.layout.activity_main);        vm = new MainActivityViewModel(this,binding);        binding.searchBtn.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                vm.setUserId("101");            }        });    }}

由于数据绑定框架正在刷新屏幕,ViewModel负责数据更改,所以我们的Activity更容易。没有更多的findViewById(),没有更多的textView.setText();和imageView.setImageResource()。你需要的只是创建一个绑定和一个ViewModel。

你可以看到,你需要做的只是更新User类,你不需要调用view.refreshUser(newUser);像MVP那样。这样,我们的分离比MVP更干净。因为ViewModel不支持View的引用,所以View和ViewModel之间的分隔更好。而ViewModel的测试与Presenter一样简单。

让开发更简单

MVVM是一种新的模式,低耦合度、双向绑定、可复用性等特性将使您的开发变得更加容易。它可以帮助您分离UI和逻辑,使单元测试可用。
当然了,本文只是个人对MVVM模式的一种浅见,实战为王,近期打算用它做一个app,到时候如果有新的发现在分享出来吧!

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 小黄车没锁被别人骑走了怎么办 幼儿早上不早起怎么办 工作中不细心怎么办 小孩没时间观念怎么办 高中厌学想回家怎么办 一年级孩子不喜欢数学怎么办 孩子做事不细心怎么办 孩子学习不够细心怎么办 孩子不用心学习怎么办? 恋爱中不够细心怎么办 孩子不愿学英语怎么办 孩子不愿学数学怎么办 孩子不愿学钢琴怎么办 小孩子学习不开窍怎么办 一年级没有读好怎么办 小孩眉毛很杂乱怎么办 孩子不好好听课怎么办 成绩差的孩子怎么办 三年级语文太差怎么办? 孩子叛逆不学习怎么办 三年级阅读理解能力差怎么办 孩子静不下心怎么办 孩子体温低于35怎么办 小孩体温突然低怎么办 宝宝35.5度体温怎么办 宝宝出汗体温低怎么办 小孩体温35.2度怎么办 孩子睡觉出冷汗怎么办 小孩感冒发烧咳嗽怎么办 小孩咳嗽出汗多怎么办 小孩手脚出汗多怎么办 小孩感冒出虚汗怎么办 宝宝感冒出冷汗怎么办 宝宝感冒睡觉出汗怎么办 宝宝感冒冒冷汗怎么办 宝宝感冒爱出汗怎么办 宝宝感冒老出汗怎么办 两只小鸡打架怎么办 老年人老是换保姆怎么办 孩子9不吃饭怎么办 两岁半宝宝不爱喝水怎么办