MVC、MVP、MVVM结合案例详解-附Demo

    本篇以登陆模块功能详解MVC、MVP、MVVM的优缺点及使用。

目录

一、MVC

1.概念

2.总结

二、MVP

 1.概念

2.总结

三、MVVM

1.概念

2.Android Data Binding

2.1 布局和绑定表达式

2.2 在子线程中更新View

2.3 实现控件TextView的点击事件

3.MVVM核心

一、MVC

1.概念

MVC全名 Model View Controller

模型(model-视图(view-控制器(controller

M是指业务模型 V是指用户界面  C则是控制器

MVC、MVP、MVVM结合案例详解-附Demo_第1张图片

2.总结

其中 View 层其实就是程序的 UI 界面,用于向用户展示数据以及接收用户的输入

Model 层就是 JavaBean 实体类,用于保存实例数据

Controller 控制器用于更新 UI 界面和数据实例

       弊端:Activity既是C又是V,既有显示UI界面,又有登陆操作。所有的代码都是在MainActivity。见Demo app。

二、MVP

 1.概念

MVP是一种经典的模式

M代表Model  V代表View   P则是PresenterModelView之间的桥梁)

MVC、MVP、MVVM结合案例详解-附Demo_第2张图片

2.总结

MVP模式的核心思想

Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口Model类还是原来的Model

作用

1.分离视图逻辑和业务逻辑,降低耦合

2.Activity只处理生命周期的任务,代码简洁

3.视图逻辑和业务逻辑抽象到了ViewPresenter中,提高阅读性

4.Presenter被抽象成接口,可以有多种具体的实现

5.业务逻辑在Presenter中,避免后台线程引用Activity导致内存泄漏

分析

1.建立3个包 model、view、Presenter分别存放对应的模型、视图、控制层。

2.Model

      定义用户名、密码,构造方法和一些set、get方法。

3.View

     UI逻辑抽象成View接口: view中UI逻辑有吐司、登陆成功或失败提示,需要定义在接口中。

4.Presenter

     业务逻辑抽象成Presenter接口:Presenter中业务逻辑有绑定和解绑View,登陆操作,需要定义在接口中。

5.实现

     在Activity和Presenter定义类,实现上述对应接口。

6.在MainActivity View中调用P接口。

7.如果有多个Activity,需要抽取共同的方法到Base接口。 要使用泛型

三、MVVM

1.概念

MVVM模式包含三个部分

-Model代表基本的业务逻辑

-View显示内容

-ViewModel将前面两者联系在一起

 

2.Android Data Binding

l2015I/O大会上谷歌介绍了一个非常NB的工具,该工具可以将View和一个对象的field绑定,当field更新的时候,framework将收到通知,然后View自动更新。

lData Binding官方原生支持MVVM模型可以让我们在不改变现有代码的框架下,非常容易的使用这些新特性。

2.1 布局和绑定表达式

(1)首先在app模块的build.gradle中加上几行代码就可以了。

android {
    …
    dataBinding {
        enabled = true
    }
}
MVC、MVP、MVVM结合案例详解-附Demo_第3张图片 插入代码前 MVC、MVP、MVVM结合案例详解-附Demo_第4张图片 插入代码后

   对比上述两个图发现添加代码后运行后会自动生成BR.class这个类。

   (2)布局文件这样写



    
        
    
    
        
    

数据中的user变量描述了可以在该布局中使用的属性。

        

布局中的表达式使用“@ {}”语法写入属性。这里,TextView文本被设置为用户变量的userName属性:

        

(3)数据对象

一个普通的对象用于描述User实体:

public class User {
    private String userName;
  
}

在数据绑定中,访问@{user.userName},那么默认就会访问同名的属性userName,或对应的getUserName方法。

(4)绑定数据

默认情况下,绑定类将基于布局文件的名称来产生 
       如布局文件为main_activity.xml,这样生成的类是 MainActivityBinding 
       如下设置Activity的contentView:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        //没有通过ID找到控件,只是对field进行操作就可以改变view的值
        ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this, R.layout.activity_main);
        final User user = new User();
        user.userName.set("dahai");
        binding.setUser(user);
        
    }

2.2 在子线程中更新View

如果在子线程直接user.setUserName("helloworld");会发现View并没有改变。那就是FrameWork并未收到通知,看文档发现需要用到可观察数据对象。

比较简单的一种方法是把User实体类变量类型改变为

public class User {
    public ObservableField userName = new ObservableField<>();
}

使用get或set来获取和设置属性值。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//        setContentView(R.layout.activity_main);
        //没有通过ID找到控件,只是对field进行操作就可以改变view的值
        ActivityMainBinding binding = DataBindingUtil.setContentView(MainActivity.this, R.layout.activity_main);
        final User user = new User();
        user.userName.set("dahai");
        binding.setUser(user);

        new Thread(new Runnable() {
            @Override
            public void run() {
                SystemClock.sleep(2000);
                user.userName.set("helloword!");
            }
        }).start();
    }

     运行后会发现:如下在子线程中更新View,FrameWork收到通知后会自动更新View。

2.3 实现控件TextView的点击事件

首先在TextView中添加属性。

        

在User类中实现点击事件方法。

    //点击TextView时弹出Log
    public void userOnClick(View view){
        Log.e("********User*******",userName.get());
    }

      点击TextView就会打印出日志Log。

3.MVVM核心

MVVM模式中,一个ViewModel和一个View匹配,它没有MVP中的IView接口,而是完全的和View绑定,所有View中的修改变化,都会自动更新到ViewModel中,同时ViewModel的任何变化也会自动同步到View上显示。

1.在build.gradle配置databinding。

2.首先新建三个包,model、view、viewmodel。在xml中更改layout。

3.viewmodel是负责M到V层,V层到M层。在viewmodel中新建MainViewModel类完成这个功能。其中包括从EtidText中拿到输入数据和点击事件。

/**
*负责M到V层,V到M层
*@author dahaiChang
*created at 2019/9/5 20:45
*/
public class MainViewModel {
    private String userName;
    private String psd;
    private Context mContext;

    public MainViewModel(Context context){
        this.mContext = context;
    }
    //从EditText拿到userName
    public TextWatcher userNameChangeListener(){
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                userName = charSequence.toString();
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        };
    }

    //从EditText拿到psd
    public TextWatcher psdChangeListener(){
        return new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {

            }

            @Override
            public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
                psd = charSequence.toString();
            }

            @Override
            public void afterTextChanged(Editable editable) {

            }
        };
    }

    //登陆点击实现
    public void login(View view){
        if (!TextUtils.isEmpty(userName) && !TextUtils.isEmpty(psd)){
            if (userName.equals("dahai") && psd.equals("123456")){

                Toast.makeText(mContext,"登陆成功!",Toast.LENGTH_LONG).show();
            }else {
                Toast.makeText(mContext,"账号或密码错误!",Toast.LENGTH_LONG).show();
            }
        }else {
            Toast.makeText(mContext,"账号或密码输入不能为空!",Toast.LENGTH_LONG).show();
        }
    }
}

本文Demo下载地址:https://github.com/dahaiChang/MVC_MVP_MVVM

你可能感兴趣的:(Android中级,MVC,MVP,MVVM)