Android——超简单 MVC、MVP、MVVM入门系列
2022年,新年第一篇文章,本篇文章将用非常简单的言语来描述各框架,尽量让大家一看即会。
前言:
相信不少伙伴在进行Android开发的时候,肯定遇见过 Activity 代码上千行的,这种代码非常难以维护,牵一发而动全身,像极了某印#国的电线杆的电线一样,网上调侃程序员修水管,越修水越多估计也是这么来的。
而框架意在将这Activity中上千行代码进行功能分类,并提高相同功能的重复使用率,我们大体可将功能简单分为三种 界面代码、业务代码、逻辑代码。让各自专一的完成各自任务。
各自负责区域
界面代码-视图层:界面绘画、界面初始化、界面事件监听、界面数据更新
业务代码-控制层:登录需求、注册需求...
逻辑代码-模型层:需求具体的实现逻辑
接下来我们来按照 Demo无框架 -> MVC -> MVP -> MVVM 的顺序来讲解一下各自的实现与区别,本章附带源码:https://github.com/1079374315/Dome_MVC_MVP_MVVM
实现的案例:
单击按钮进行单机登录,这个例子够简单了吧,我们来看看不用框架实现时的情况。
(本代码均简易实现,不进行复杂的逻辑判断,意在将代码简化让读者更好的理解框架)
我们先看看总体结构:
公共类介绍:
实体类
数据库封装类
反馈接口
Demo无框架
public class Demo_Activity extends AppCompatActivity implements View.OnClickListener {private TextView tv_showData;private EditText et_userName;private EditText et_passWord;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);initView();}private void initView() {tv_showData = findViewById(R.id.tv_showData);et_userName = findViewById(R.id.et_userName);et_passWord = findViewById(R.id.et_passWord);findViewById(R.id.btn_login).setOnClickListener(this);}@Overridepublic void onClick(View v) {loginRequest(getLoginData(), new OnLoginCallback() {@SuppressLint("SetTextI18n")@Overridepublic void onSuccess(LoginBean MVVMLoginBean) {tv_showData.setText("登录成功:" + MVVMLoginBean.toString());}@Overridepublic void onError() {tv_showData.setText("登录失败,账号密码错误!");}});}//获取登录数据private LoginBean getLoginData() {String userName = et_userName.getText().toString();String passWord = et_passWord.getText().toString();return new LoginBean(userName, passWord);}//登录请求private void loginRequest(LoginBean MVVMLoginBean, OnLoginCallback loginCallback) {if (SQL_Utils.userName.equals(MVVMLoginBean.getUserName()) && SQL_Utils.passWord.equals(MVVMLoginBean.getPassWord())) {//登录成功loginCallback.onSuccess(MVVMLoginBean);} else {//登录失败loginCallback.onError();}}}
Footer
用以上代码就可以实现一个登录实例,我们将这个代码图解一下:
界面代码-视图层:界面绘画、界面初始化、界面事件监听、界面数据更新
业务代码-控制层:登录需求、注册需求...
逻辑代码-模型层:需求具体的实现逻辑
目前我们可以看到 界面代码、业务代码、逻辑代码 这些代码均在同一个界面,当我们这个界面功能变多了,那这个Activity将会越来越臃肿,变得难以维护。
现在我们用 MVC 来看看如何把他进行解耦优化。
MVC模式:
(先解释一下箭头)
View -> Controller 表示:Controller持有 View类的引用,单向则表示,Controller可调用View类中方法,但View无法调用Contriller, 后面的Controller -> Model 也一样。
界面代码-视图层-View:界面绘画、界面初始化、界面事件监听、界面数据更新
业务代码-控制层-Controller:登录需求、注册需求...
逻辑代码-模型层-Model:需求具体的实现逻辑
我们先看看总体结构:
公共类还是用之前的,MVC就新增了两个类,Activity 与 Model
MVC_Model
/*** author:hello* time:2020/7/31* CSDN: qq_39799899* explain:**/
public class MVC_Model {//登录请求public void loginRequest(LoginBean loginBean, OnLoginCallback loginCallback) {if (SQL_Utils.userName.equals(loginBean.getUserName()) && SQL_Utils.passWord.equals(loginBean.getPassWord())) {//登录成功loginCallback.onSuccess(loginBean);} else {//登录失败loginCallback.onError();}}}
MVC_Activity
public class MVC_Activity extends AppCompatActivity implements View.OnClickListener {private TextView tv_showData;public EditText et_userName;public EditText et_passWord;private MVC_Model mvc_model;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);initView();mvc_model = new MVC_Model();}private void initView() {tv_showData = findViewById(R.id.tv_showData);et_userName = findViewById(R.id.et_userName);et_passWord = findViewById(R.id.et_passWord);findViewById(R.id.btn_login).setOnClickListener(this);}@Overridepublic void onClick(View v) {mvc_model.loginRequest(getLoginData(), new OnLoginCallback() {@SuppressLint("SetTextI18n")@Overridepublic void onSuccess(LoginBean loginBean) {tv_showData.setText("登录成功:" + loginBean.toString());}@Overridepublic void onError() {tv_showData.setText("登录失败,账号密码错误!");}});}//获取登录数据public LoginBean getLoginData() {String userName = et_userName.getText().toString();String passWord = et_passWord.getText().toString();return new LoginBean(userName, passWord);}}
我们MVC图解一下:
界面代码-视图层:界面绘画、界面初始化、界面事件监听、界面数据更新
业务代码-控制层:登录需求、注册需求...
逻辑代码-模型层:需求具体的实现逻辑
在MVC的体系上是不是发现,逻辑层代码已经被搬离出去了,这里就做到了逻辑代码的解耦,接下来我们再分析一下逻辑层MVC_Model里的代码
只需要调用者提供数据源与反馈数据接口,不管是那个Activity,都可以继续重用该业务逻辑代码,这样是不是一下就提高了代码的重复利用性,降低了代码的耦合性,而且今后改逻辑也只需要改一处就好。
我们再来看看项目中自带的MVC文档
MVC缺点也确实很明显,逻辑代码确实已经被搬离出去了,但控制层的代码的代码依旧还在Activity中,接下来我们来看看如何将这控制层的代码也搬离出去,进行更优的解耦。
MVP模式:
(先解释一下箭头)
View →← Presenter表示:Presenter与View类 相互持有彼此的引用,Controller可调用View类中方法,且View同样也可调用Presenter方法, 后面的Controller -> Model 也一样。
Presenter意在将MVC中 View 持有Model引用给完全隔离掉,View 与 Model之间交互完全由Presenter来帮助与协调。
MVC示意图
我们先看看总体结构
公共类上面已介绍过了,我们继续来看看MVP这些接口
Model 与 上面MVC里介绍的Model 没有变化
/*** author:hello* time:2020/7/31* CSDN: qq_39799899* explain:**/
public class MVP_Model {//登录请求public void loginRequest(LoginBean loginBean, OnLoginCallback loginCallback) {if (SQL_Utils.userName.equals(loginBean.getUserName()) && SQL_Utils.passWord.equals(loginBean.getPassWord())) {//登录成功loginCallback.onSuccess(loginBean);} else {//登录失败loginCallback.onError();}}}
MVP_View
/*** author:hello* time:2020/8/1* CSDN: qq_39799899* explain:主要负责View数据的 获取 与 赋值**/
public interface MVP_View extends OnLoginCallback{LoginBean getLoginData();}
接下来我们来看看Presenter如何来协调 MVP_View 与 MVP_Model 的
/*** author:hello* time:2020/8/1* CSDN: qq_39799899* explain:**/
public class MVP_Presenter {private MVP_View mvp_view;private MVP_Model mvp_model;public MVP_Presenter(MVP_View mvp_view) {this.mvp_view = mvp_view;this.mvp_model = new MVP_Model();}public void login(LoginBean loginBean) {mvp_model.loginRequest(loginBean, new OnLoginCallback() {@Overridepublic void onSuccess(LoginBean MVVMLoginBean) {mvp_view.onSuccess(MVVMLoginBean);}@Overridepublic void onError() {mvp_view.onError();}});}}
我们来看看图解:
接下来我们来看看 业务代码与逻辑代码都被解耦了,那Activity还有什么事呢?
/*** 主要负责初始化数据*/
public class MVP_Activity extends AppCompatActivity implements View.OnClickListener, MVP_View {private TextView tv_showData;public EditText et_userName;public EditText et_passWord;private MVP_Presenter mvp_presenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);tv_showData = findViewById(R.id.tv_showData);et_userName = findViewById(R.id.et_userName);et_passWord = findViewById(R.id.et_passWord);findViewById(R.id.btn_login).setOnClickListener(this);mvp_presenter = new MVP_Presenter(this);}@Overridepublic void onClick(View v) {mvp_presenter.login(getLoginData());}@Overridepublic LoginBean getLoginData() {String userName = et_userName.getText().toString();String passWord = et_passWord.getText().toString();return new LoginBean(userName, passWord);}@Overridepublic void onSuccess(LoginBean MVVMLoginBean) {tv_showData.setText("登录成功:" + MVVMLoginBean.toString());}@Overridepublic void onError() {tv_showData.setText("登录失败,账号密码错误!");}
}
这张图解是不是发现大多数都是界面代码没发现有逻辑代码了,因为逻辑代码已经被解耦到 Presenter里去了,View没有Model的引用了。
而且你细心一点就会发觉,MVP_View 这个接口也是可以多次实现的,也就是说,目前的Presenter也是可以复用,Model也是可以复用的。
界面代码-视图层:界面绘画、界面初始化、界面事件监听、界面数据更新
业务代码-控制层:登录需求、注册需求...
逻辑代码-模型层:需求具体的实现逻辑
MVP示意图
MVP不愧是MVC的升级版,更加提升了框架代码的复用性
我们来看看MVP的文档
其实MVP已经很优解了,解耦性也比较不错了,但我们还有更优解的 MVVM模式且不用写那么多接口,代码量也更少
MVVM模式:
(先解释一下箭头)
View ↔ ViewModel表示:View与ViewModel相互绑定,然后ViewModel与Model又相互持有彼此引用,相互持有引用相信大家已经非常熟悉了,但这相互绑定是怎样的,没了解过的伙伴估计不太理解。
相互绑定的话,View可以通过 ViewModel 从 Model 中获取数据;当获取到了数据之后,会通过自动绑定相互绑定的作用,设置到View界面展示。
相互绑定的作用:可以省去 组件获取、事件注册、数据获取、数据更新这些代码。我们来看看之前MVP中Activity代码,除去Presenter代码与Model代码,View代码里剩下的全是组件获取、事件注册、数据获取、数据更新了,而MVVM就是省去这些代码。
MVP Activity代码
我们先看看总体结构:
想要实现MVVM就得 打开DataBindingUtil :找到.app
在android{}下添加开启:
然后我们再来看看MVVM 的 Model,铁打的Model 流水的View, Model层与MVC、MVP的Model一样。
Model
public class MVVM_Model {private SQLUtils sqlUtils;public MVVM_Model() {sqlUtils = new SQLUtils();} //登录请求 public void loginRequest(LoginBean loginBean, OnLoginCallback loginCallback) {if (sqlUtils.queryUserName().equals(loginBean.getUserName()) && sqlUtils.queryPassWord().equals(loginBean.getPassWord())) { //登录成功 loginCallback.onSuccess(loginBean);} else { //登录失败 loginCallback.onError();}}
}
我们再来看看 ViewModel 是如何与View互相绑定的
ViewModel
public class MVVM_ViewModel extends BaseObservable {private MVVM_Model mvvm_model;private String result;private ActivityMvvmBinding binding; //该方法由View界面自动调用 @Bindablepublic String getResult() {return result;} //设置结果到View界面并刷新 public void setResult(String result) {this.result = result;notifyPropertyChanged(BR.result);} //构造方法初始化 public MVVM_ViewModel(ActivityMvvmBinding binding) {mvvm_model = new MVVM_Model();this.binding = binding;} //通过binding获取数据 public LoginBean getLoginBean() {return new LoginBean(binding.etUserName.getText().toString(), binding.etPassWord.getText().toString());} //View界面注册的单击事件 public void loginRequest(View view) {mvvm_model.loginRequest(getLoginBean(), new OnLoginCallback() {@Overridepublic void onSuccess(LoginBean loginBean) {setResult("获取成功:" + loginBean.toString());}@Overridepublic void onError() {setResult("获取失败:账号或密码错误!");}});}
}
我们来图解一下:图有点大,但放大看还是看的很透彻的
看完这张图你应该可以明白,View与ViewModel是如何绑定的了吧。
那我们再来看看此时的Activity还负责那些代码
仅负责 View 与 ViewModel 之间的绑定后,就做甩手掌柜了。
现在是不是感觉代码少了很多很多。
小伙伴门可以将Model 静态化试试,将会有新的发现。
博主将 MVC MVP MVVM 的辅助方法加入了GT库中,在MVVM的基础上更优解,感兴趣的小伙伴们可 下载MVVM-GT版 进行查看
本章演示源码:GitHub - 1079374315/Dome_MVC_MVP_MVVM
MVVM-GT库版源码:GitHub - 1079374315/MVC_MVP_MVVM_GT
Android——超简单 MVC、MVP、MVVM入门系列相关推荐
- Android 开发架构-MVC MVP MVVM详解
何为架构 架构,即程序的逻辑组织结构,是指导开发过程中划分程序逻辑模块的关键,好的架构要使程序达到高内聚低耦合的设计目标.例如一个人,身体的骨骼即为身体的架构,有了基本骨架之后,才可以决定在头颅里开发 ...
- Android App的设计架构:MVC,MVP,MVVM与架构经验谈
本文转载自https://www.tianmaying.com/tutorial/AndroidMVC,原文作者周鸿博. 和MVC框架模式一样,Model模型处理数据代码不变在Android的App开 ...
- Android中常见的MVC/MVP/MVVM模式
Android中常见的MVC/MVP/MVVM模式 经典MVC 在1979年,经典MVC模式被提出. 在当时,人们一直试图将纯粹描述思维中的对象与跟计算机环境打交道的代码隔离开来,而Trygve Re ...
- Android架构设计之MVC/MVP/MVVM浅析
目录 写在前面 一.案例演示 二.MVC模式 2.1.MVC简介 2.2.MVC模式的使用 2.3.MVC模式的缺点 三.MVP模式 3.1.MVP简介 3.2.MVP模式的作用 3.3.MVP模式的 ...
- Android 系统(77)---MVC,MVP,MVVM的区别
MVC,MVP,MVVM的区别 一.MVC 软件可以分为三部分 1.Model:模型层,负责处理数据的加载或者存储 2. View:视图层,负责界面数据的展示,与用户进行交互 3.Controll ...
- [Android答答答]什么是MVC/MVP/MVVM
什么是MVC/MVP/MVVM? 概念 1.MVC是什么? 2.MVP是什么 3.MVVM是什么 原理 1.MVC的特点是什么 2.MVP的特点是什么 3.MVVM的特点是什么 概念 1.MVC是什么 ...
- MVC---Android App的设计架构:MVC,MVP,MVVM与架构经验谈
转载自: http://www.tianmaying.com/tutorial/AndroidMVC 1.架构设计的目的 通过设计使程序模块化,做到模块内部的高聚合和模块之间的低耦合.这样做的好处是使 ...
- iOS-【转载】架构模式 - 简述 MVC, MVP, MVVM 和 VIPER
看了很多篇关于 iOS 架构模式的,尤其是关于 MVVM 的,都是似懂非懂,无意看见了这篇,发现总结的很到位,很用心,特转载至此,如果英语好,请看原文 iOS Architecture Pattern ...
- iOS-【转载】架构模式 - 简述 MVC, MVP, MVVM 和 VIPER (译)
看了很多篇关于 iOS 架构模式的,尤其是关于 MVVM 的,都是似懂非懂,无意看见了这篇,发现总结的很到位,很用心,特转载至此,如果英语好,请看原文 iOS Architecture Pattern ...
最新文章
- 计算机等级考试2018改革,2018全国计算机等级考试调整方案公布,这些科目取消了!...
- python之禅中文-python之禅
- mysql5.7版本安装部署详细步骤
- 让Sql Server也能出现如VS一样的智能提示工具--资源更新
- 法院才是最童叟无欺的一元店
- 挂载jffs2文件系统遇到的问题
- angular2学习笔记之服务和http
- OpenCV案例(二):选取圆对象
- php中对数组进行转码,php实现转码的方式(支持数组类型转码)
- java程序设计中科院_中科院NLPIR中文分词java版
- 项目管理--maven浅析《四》之私服(Nexus)
- Cocos2d-x 整理 SDK,易接流程(写给自己看的
- IE浏览器为什么打不开java_IE浏览器拒绝访问的原因及其解决方法。
- linux飞行模式命令,Android 开启飞行模式的几种方式
- 关闭windows defender
- 期权:短期交易日内波动为主 静待市场情绪拐点
- ps的两种填充效果快捷键
- 小苹果软件_汪峰女儿小苹果晒原创音乐,完美遗传音乐基因,粉丝:何时出道?...
- Apache Kylin 之 初介绍
- asp毕业设计—— 基于asp+access的网络招聘管理系统设计与实现(毕业论文+程序源码)——网络招聘管理系统
热门文章
- 不会python怎么办,这样大数据数据分析,小白也能上手
- 命令行简单使用一下PMD【win和linux双系统】【JAVA静态代码审查工具】
- 如何做微信视频号定位?视频号账号定位怎么做?国仁网络资讯
- OSSEC解决IO占满问题
- Linux常用命令——远程传输文件(scp/rsync)
- 【MARK】个人装机软件备份(上)
- 最大流最小割经典例题_最大流, 最小割问题及算法实现
- 因为文件共享不安全,所以你不能连接到文件共享。此共享需要过时的SMB1协议,而此协议是不安全的,可能会使你的系统遭受攻击。 你的系统需要SMB2或更高版本。
- 2013年JavaA组
- MySQL 模块五、模块六复习笔记