Android学习笔记整理之常用三种框架:3、MVVM模式

 

MVVM框架模型

本节将带大家总结 MVP 框架模型存在的问题,通过对比的方式学习 MVVM 模型,

并使用 MVVM 模型实现对需求的再一步优化,最后总结MVVM的优缺点。

上面我们讲了 mvp 模型,mvp 对 mvc 进行了比较好的优化,并且在日常的项目代码中,

mvp 已经能够帮助我们满足大部分的场景需求,但是它还不够简洁,需要使用较多的接口,

所以我们希望可以对它进行进一步的优化。

 

mvp 和 mvvm的异同点

下面我们来看看mvvm框架模型

首先我们会发现 mvvm 的模型图和 mvp 的模型图是非常相似的,唯一的区别就是将 Presenter 替换成了 ViewModel,

实际上确实是这样的,mvvm 和 mvp 在思想上是非常接近的,但是在代码逻辑上 mvvm 会显得更加的简洁。

下面我们就具体来看一下mvvm

 mvvm 相对于 mvp 减少了接口数量,并且因为使用了数据绑定 DataBinding,

所以 mvvm 可以告别繁琐的 findViewByid 的操作。

因此在进一步学习 mvvm 之前,我们需要先学习下 DataBinding。

详细可参考我的博文:DataBinding的基本用法

 

使用MVVM实现需求

上面我们学习了 DataBinding 的基本用法,接下来我们继续MVVM模型的代码实战部分

使用MVVM实现需求,我们还是需要三层:Model层(M)、View层(V)、ViewModel层(VM)

View层:

主要负责视图相关的功能,主要代表的还是Activity以及layout布局文件

Model层:

主要负责数据的获取

ViewModel层:

作为中间纽带层,实现一些业务逻辑相关的功能,

并且在MVVM模型中ViewModel层还需要负责数据更新,

以保证当数据发生变化的时候,视图可以得到及时的更新。

总体来说 :

1、MVVM 和 MVP 是非常相似的,不同的是在 MVVM 中使用 DataBinding 进行了数据的绑定,

所以 View 层的主要负责人,就从 Activity 变为了 layout ,layout 的功能变得非常的强大,

可以在布局文件中直接使用数据 ,很多的功能我们也可以直接放到 layout 中去实现,

这样就大大的简化了 Activity 里面的功能实现,可能 Activity 只需帮我们做一些初始化的工作。

2、还有一点不同的是在 MVVM 模型中,View 与 ViewModel 使用 DataBinding 进行通信,

比如我们可以在布局文件中声明 ViewModel,这样就能在布局文件中直接引用 ViewModel 中的数据,

这样做也可以简化 ViewModel 中的功能,一部分的逻辑可以放到布局文件中去实现。

 

使用MVVM实现需求-主要步骤

 

第一步,我们需要在代码中提供 View、ViewModel 以及 Model 三层。

这里我们创建了三个类:MVVMActivity、MVVMModel、MVVMViewModel

其中 MVVMActivity 使用的布局就是之前 NormalActivity 的布局文件

 

第二步,将布局文件修改为 DataBinding 布局

1、添加语句启动DataBinding

我们之前有讲过参见: 步骤1:添加语句启用 DataBinding

2、布局文件修改为 DataBinding 布局

我们之前有讲过参见:步骤3:如何将传统布局转换为DataBinding布局?

第三步,需要实现 View 与 ViewModel 之间通过 DataBinding 进行通信

1、写 MVVMModel 类

 

2、写 MVVMActivity 类

 

第四步,获取数据并展示在界面上

1、activity_main.xml 布局进行变量和方法的绑定

EditText与变量进行双向绑定

Button与方法进行绑定

TextView与变量绑定

 

具体代码如下:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <!--
        声明MVVMViewModel
        选中类名,右键,Copy Reference可直接复制此包名+类名
    -->
    <data>
        <variable
            name="viewModel"
            type="com.yyh.testmode5_mvvm.mvvm.MVVMViewModel" />

    </data>


    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context=".normal.NormalActivity">

        <!--EditText与变量进行双向绑定:
            绑定userInput字段,所以我们加了一个等号,
            当数据发生变化的时候,这个输入框会发生变化,会自动更新。
            同时当用户输入的时候,也就是视图发生变化的时候,
            viewModel中的userInput数据也会自动的发生变化。
        -->
        <EditText
            android:id="@+id/et_account"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:hint="请输入要查询的账号"
            android:text="@={viewModel.userInput}"
            />

        <!--
            Button与方法进行绑定:
            android:onClick="@{viewModel.getData}"
            为按钮添加点击事件,表示当点击按钮的时候,
            调用ViewModel(MVVMViewModel)中的getData方法。
            也就是说此按钮与getData方法,进行了绑定。
         -->
        <Button
            android:id="@+id/btn_getAccount"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:layout_gravity="center_horizontal"
            android:text="获取账号信息"
            android:onClick="@{viewModel.getData}"
            />

        <!--
            TextView与变量绑定:
            把文本框与ViewModel(MVVMViewModel)中的result变量进行绑定
            前提:
            在ViewModel(MVVMViewModel)中需要定义一个变量叫result,
            同时写它的get/set方法
         -->
        <TextView
            android:id="@+id/tv_result"
            android:layout_marginTop="50dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:hint="账号信息暂时未获取"
            android:text="@{viewModel.result}"
            />

    </LinearLayout>
</layout>

 

 

2、写类 MVVMViewModel

这个就不具体多说了,注释已经比较详细了

// 为了实现数据发生变化,视图自动更新
// 1、继承BaseObservable、
// 2、在get方法中,添加注解@Bindable、
// 3、在set方法中,调用更新方法notifyPropertyChanged
public class MVVMViewModel extends BaseObservable {

    //在 activity_mvvm 布局中,TextView对它进行了绑定
    private String result;
    private MVVMModel mvvmModel;
    private ActivityMvvmBinding binding;
    //在 activity_mvvm 布局中,EditText对它进行了双向绑定
    private String userInput;

    //一般需要传入Application对象,
    //方便在ViewModel中使用application
    //比如sharedpreferences需要使用
    public MVVMViewModel(Application application) {
        mvvmModel = new MVVMModel();
    }

    public MVVMViewModel(Application application, ActivityMvvmBinding binding) {
        mvvmModel = new MVVMModel();
        this.binding = binding;
    }



    /**
     * 在 activity_mvvm 布局中的Button按钮,已经对此getData方法进行了绑定,
     * 当我们点击按钮,就会执行此方法
     * @param view
     */
    public void getData(View view){

        //userInputGetValue1();
        userInputGetValue2();

    }

    private void userInputGetValue1() {

        String userInput = binding.etAccount.getText().toString().trim();
        //上面这里是使用binding直接在MVVMViewModel里面进行操作,这样写也不是特别的好
        //我们也可以在布局文件EditText中进行绑定,详见 userInputGetValue2 方法

        mvvmModel.getAccountData(userInput, new MCallback() {
            @Override
            public void onSuccess(Account account) {
                String info = account.getName() + "|"+account.getLevel();
                setResult(info);
            }

            @Override
            public void onFailed() {
                setResult("获取数据失败");
            }
        });

    }

    private void userInputGetValue2() {

        //String userInput = binding.etAccount.getText().toString().trim();
        //上面这里是使用binding直接在MVVMViewModel里面进行操作,这样写也不是特别的好。

        //我们可以进行改进,在布局文件 EditText 中进行双向绑定,所以这句可以注释了,
        //然后我们也不需要引入 binding 对象了,可以把它删除掉,实现更好的解耦。

        mvvmModel.getAccountData(userInput, new MCallback() {
            @Override
            public void onSuccess(Account account) {
                String info = account.getName() + "|"+account.getLevel();
                setResult(info);
            }

            @Override
            public void onFailed() {
                setResult("获取数据失败");
            }
        });

    }


    @Bindable
    public String getResult() {
        return result;
    }

    public void setResult(String result) {
        this.result = result;
        notifyPropertyChanged(BR.result);
    }

    @Bindable
    public String getUserInput() {
        return userInput;
    }

    public void setUserInput(String userInput) {
        this.userInput = userInput;
        notifyPropertyChanged(BR.userInput);
    }


}

当点击按钮的时候,会自动调用getData方法,我们希望在里面获取数据,

这时我们需要得到 MVVMModel 对象,来调用它里面的 getAccountData方法

布局中的 EditText 输入框,和MVVMViewModel 的 userInput 变量进行绑定,

它们进行了双向绑定,也就是当数据发生变化的时候,EditText 输入框会发生变化自动更新,

同时当用户在界面 EditText 输入框,输入内容的时候,MVVMViewModel 的 userInput 变量的数据,也会对应发生变化。

 

我们的 View 现在可以向 ViewModel 传递信息,比如说当点击按钮的时候,可以向 ViewModel 调用 getData 方法。

ViewModel 也可以通过改变数据,比如 result、userInput,当改变数据以后,就可以通知视图进行自动更新。

 

但是有时候有些功能我们需要放到 Activity 中去做,这样就会出现一个问题,比如我们在 Activity 中当点击按钮的时候,

我们需要做一些申请权限的操作,那么这个时候 ViewModel 如何通知 Activity 去做这件事情呢?

我们可以让 ViewModel 持有 Activity 的引用,或者说是借用第三方库比如 EventBus 等,

但是这样做都不是非常好,对于 MVVM 模型我们还是建议:LiveData+ ViewModel 的方式去实现。

为什么要使用 LiveData 呢?

所以对于 MVVM 模式要想使用的好,需要学习的东西还是挺多的。

 

MVVM的优缺点

优点:

相对于MVP,MVVM实现了数据和视图的双向绑定,极大的简化了我们的代码。

缺点:

bug 难以调试,并且 dataBinding 目前还存在一些编译的问题。

所以大家要慎重选择判断,要想使用好 MVVM,我们可以把 DataBinding 和 LiveData 先学好,

因为 DataBinding 是实现 MVVM 模式数据绑定的工具,

LiveData 可以更好的解决 MVVM 模式之间的通信问题,并且它可以感知组件的生命周期,能够有效的避免内存泄露问题。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

被开发耽误的大厨

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值