本篇以登陆模块功能详解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则是控制器

2.总结

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

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

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

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

二、MVP

1.概念

MVP是一种经典的模式

M代表Model  V代表View   P则是Presenter(Model和View之间的桥梁)

2.总结

MVP模式的核心思想

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

作用

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

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

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

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

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

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

2.1 布局和绑定表达式

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

android {…dataBinding {enabled = true}
}

插入代码前

插入代码后

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

(2)布局文件这样写

<?xml version="1.0" encoding="utf-8"?>
<layoutxmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"><data><variablename="user"type="m.cyh.com.mvvm.User"/></data><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"tools:context=".MainActivity"><TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.userName}" /></LinearLayout>
</layout>

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

        <variablename="user"type="m.cyh.com.mvvm.User"/>

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

        <TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.userName}" />

(3)数据对象

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

public class User {private String userName;}

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

(4)绑定数据

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

    @Overrideprotected 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<String> userName = new ObservableField<>();
}

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

    @Overrideprotected 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() {@Overridepublic void run() {SystemClock.sleep(2000);user.userName.set("helloword!");}}).start();}

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

2.3 实现控件TextView的点击事件

首先在TextView中添加属性。

        <TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="@{user.userName}"android:onClick="@{user.userOnClick}"/>

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

    //点击TextView时弹出Logpublic 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拿到userNamepublic TextWatcher userNameChangeListener(){return new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}@Overridepublic void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {userName = charSequence.toString();}@Overridepublic void afterTextChanged(Editable editable) {}};}//从EditText拿到psdpublic TextWatcher psdChangeListener(){return new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {}@Overridepublic void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {psd = charSequence.toString();}@Overridepublic 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

MVC、MVP、MVVM结合案例详解-附Demo相关推荐

  1. java struts json_struts2的json插件配置详解(附demo)

    为了方便ajax调用传输数据,在struts2中加入的json插件用来做对象的序列化和反序列化,json插件的下载地址 1. 下载json插件包,将jar包拷贝到WEB-INF/lib目录 注:str ...

  2. 23种设计模式详解与示例代码(详解附DEMO)

    设计模式在Java中的应用与实现

  3. wow mysql dbc_DBC中悲观锁介绍附案例详解

    DBC中悲观锁介绍附案例详解 了解下DBC中悲观锁: 代码如下: BDUtils 工具类: package JDBC; import java.sql.*; public class BDUtils ...

  4. 【Spring AOP】@Aspect结合案例详解(二): @Pointcut使用@within和within(已附源码)

    文章目录 前言 @within 完善打印日志案例 @within深入说明 within 匹配指定类 匹配指定包(package) 源码下载 总结 前言 在微服务流行的当下,在使用Spring Clou ...

  5. java递归函数例子_Java递归函数详解附案例

    递归函数在Java语言中得到了广泛的应用,它使得程序的编写过程更加的清晰明了.对Java初学者来讲,递归函数是需要学习的一个重要知识点.本文将附上案例和演示代码,具体为大家介绍递归函数的概念.要素以及 ...

  6. Android架构设计之MVC/MVP/MVVM浅析

    目录 写在前面 一.案例演示 二.MVC模式 2.1.MVC简介 2.2.MVC模式的使用 2.3.MVC模式的缺点 三.MVP模式 3.1.MVP简介 3.2.MVP模式的作用 3.3.MVP模式的 ...

  7. android mvp模式例子_Android中mvp模式使用实例详解

    MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一 ...

  8. 视频教程-React Hooks 案例详解(React 进阶必备)-其他

    React Hooks 案例详解(React 进阶必备) Leo 1978年8月生,河北石家庄人. 曾任职中软股份. 计算科学导师: 刘坤起博士. 开发的<电商分销系统>获得淘宝Top10 ...

  9. python代码案例详解-我用Python抓取了7000 多本电子书案例详解

    安装 安装很简单,只要执行: pip install requests-html 就可以了. 分析页面结构 通过浏览器审查元素可以发现这个电子书网站是用 WordPress 搭建的,首页列表元素很简单 ...

最新文章

  1. 聊一聊 Spring 中的线程安全性
  2. 分布式系统之消息队列
  3. 若依部署上线之后验证码不显示的解决方法之一
  4. elasticsearch 问题
  5. Android笔记-Xposed的使用(Hook登录函数获取用户名密码)
  6. vss团队开发工具使用(个人学习心得)
  7. (22)FPGA比较器设计(第5天)
  8. NBU 备份系统详细操作手册之维护与安装
  9. python 中in
  10. 压力测试 - HTTP压测工具stress指南
  11. java中io的重要性_java中的IO整理
  12. dpi和ppi换算_十分钟快速理解DPI和PPI,不再傻傻分不清!
  13. 【时间序列】ICDE 2021丨时间序列相关研究论文汇总
  14. jdk常用工具命令总结
  15. 第一代电子计算机采用的物理器,第一章 计算机基础知识
  16. UTC、GMT、时间戳之间的关系
  17. SQL 面试题:WHERE 和 HAVING、ON 有什么区别?
  18. 高效解锁Word文档密码
  19. 第一节项目整体管理学习笔记
  20. Ceph-rbd排错

热门文章

  1. 如何证明e进制计算机最快,第一讲:计算机基础知识回顾--(进制与编码2)
  2. Spring.NET 1.3.0公布平添新特征
  3. 学习笔记(10):第一章: 路由与模板-Web前端技术与框架 5
  4. php 秒嘀短信验证码
  5. vue.config.js中public是什么意思?
  6. 世界顶尖3D Web端渲染引擎:HOOPS Communicator技术介绍(一)
  7. gurobi 的过期总结
  8. TensorFLow 数学运算
  9. python博弈树_简单博弈树算法(nim游戏)
  10. kotlin读书笔记之函数基本知识以及泛型