• 售前

  • 售后

热门帖子
入门百科

Android——超简朴 MVC、MVP、MVVM入门系列

[复制链接]
东阿制造 显示全部楼层 发表于 2022-1-16 07:22:17 |阅读模式 打印 上一主题 下一主题
2022年,新年第一篇文章,本篇文章将用非常简朴的言语来形貌各框架,只管让各人一看即会。




媒介:

信赖不少同伴在举行Android开辟的时间,肯定遇见过 Activity 代码上千行的,这种代码非常难以维护,牵一发而动满身,像极了某印#国的电线杆的电线一样,网上挖苦步伐员修水管,越修水越多估计也是这么来的。
而框架意在将这Activity中上千行代码举行功能分类,并进步雷同功能的重复利用率,我们大要可将功能简朴分为三种 界面代码、业务代码、逻辑代码。让各自笃志的完成各自任务。
各自尊责地区
界面代码-视图层:界面绘画、界面初始化、界面事故监听、界面数据更新
业务代码-控制层:登录需求、注册需求...
逻辑代码-模子层:需求详细的实现逻辑
接下来我们来按照 Demo无框架 -> MVC -> MVP -> MVVM 的序次来解说一下各自的实现与区别,本章附带源码https://github.com/1079374315/Dome_MVC_MVP_MVVM
实现的案例:













单击按钮举行单机登录,这个例子够简朴了吧,我们来看看不消框架实现时的环境。
(本代码均浅显实现,不举行复杂的逻辑判定,意在将代码简化让读者更好的明白框架)
我们先看看总体结构:

公共类先容:

实体类

数据库封装类

反馈接口
 


Demo无框架

  1. public class Demo_Activity extends AppCompatActivity implements View.OnClickListener {
  2.     private TextView tv_showData;
  3.     private EditText et_userName;
  4.     private EditText et_passWord;
  5.     private SQLUtils sqlUtils;
  6.     @Override
  7.     protected void onCreate(Bundle savedInstanceState) {
  8.         super.onCreate(savedInstanceState);
  9.         setContentView(R.layout.activity_login);
  10.         initView();//初始化UI组件
  11.         sqlUtils = new SQLUtils();//初始化数据库操作类
  12.     }
  13.     private void initView() {
  14.         tv_showData = findViewById(R.id.tv_showData);
  15.         et_userName = findViewById(R.id.et_userName);
  16.         et_passWord = findViewById(R.id.et_passWord);
  17.         findViewById(R.id.btn_login).setOnClickListener(this);//注册单击事件
  18.     }
  19.     @Override
  20.     public void onClick(View v) {
  21.         //单击进行登录
  22.         loginRequest(getLoginData(), new OnLoginCallback() {
  23.             @SuppressLint("SetTextI18n")
  24.             @Override
  25.             public void onSuccess(LoginBean loginBean) {
  26.                 tv_showData.setText("登录成功:" + loginBean.toString());
  27.             }
  28.             @Override
  29.             public void onError() {
  30.                 tv_showData.setText("登录失败,账号密码错误!");
  31.             }
  32.         });
  33.     }
  34.     //获取登录数据
  35.     private LoginBean getLoginData() {
  36.         String userName = et_userName.getText().toString();
  37.         String passWord = et_passWord.getText().toString();
  38.         return new LoginBean(userName, passWord);
  39.     }
  40.     //登录请求,将数据与数据库的数据进行对比
  41.     private void loginRequest(LoginBean loginBean, OnLoginCallback loginCallback) {
  42.         if (sqlUtils.queryUserName().equals(loginBean.getUserName()) &&
  43.                 sqlUtils.queryPassWord().equals(loginBean.getPassWord())) {
  44.             //登录成功
  45.             loginCallback.onSuccess(loginBean);//调用接口反馈成功数据
  46.         } else {
  47.             //登录失败
  48.             loginCallback.onError();//调用接口反馈失败数据
  49.         }
  50.     }
  51. }
复制代码
用以上代码就可以实现一个登录实例,我们将这个代码图解一下:
界面代码-视图层:界面绘画、界面初始化、界面事故监听、界面数据更新
业务代码-控制层:登录需求、注册需求...
逻辑代码-模子层:需求详细的实现逻辑

 现在我们可以看到 界面代码、业务代码、逻辑代码 这些代码均在同一个界面,当我们这个界面功能变多了,那这个Activity将会越来越痴肥,变得难以维护。
现在我们用 MVC 来看看怎样把他举行解耦优化。


MVC模式:








(先表明一下箭头)
View -> Controller 表现:Controller持有 View类的引用,单向则表现,Controller可调用View类中方法,但View无法调用Contriller, 反面的Controller -> Model 也一样。
界面代码-视图层-View:界面绘画、界面初始化、界面事故监听、界面数据更新
业务代码-控制层-Controller:登录需求、注册需求...
逻辑代码-模子层-Model:需求详细的实现逻辑
我们先看看总体结构:

 公共类还是用之前的,MVC就新增了两个类,Activity 与 Model
MVC_Model
  1. /**
  2. * author:hello
  3. * time:2020/7/31
  4. * CSDN: qq_39799899
  5. * explain:其实就是将与UI无关的事情移至到 Mvc_Model中
  6. * 如:网络请求、数据获取、查询等
  7. **/
  8. public class MVC_Model {
  9.     private SQLUtils sqlUtils;
  10.     public MVC_Model(){
  11.         sqlUtils = new SQLUtils();//初始化数据库封装类
  12.     }
  13.     //登录请求,将数据与数据库的数据进行对比
  14.     public void loginRequest(LoginBean loginBean, OnLoginCallback loginCallback) {
  15.         if (sqlUtils.queryUserName().equals(loginBean.getUserName()) &&
  16.                 sqlUtils.queryPassWord().equals(loginBean.getPassWord())) {
  17.             //登录成功
  18.             loginCallback.onSuccess(loginBean);
  19.         } else {
  20.             //登录失败
  21.             loginCallback.onError();
  22.         }
  23.     }
  24. }
复制代码
MVC_Activity
  1. public class MVC_Activity extends AppCompatActivity implements View.OnClickListener {
  2.     private TextView tv_showData;
  3.     private EditText et_userName;
  4.     private EditText et_passWord;
  5.     private MVC_Model mvc_model;
  6.     @Override
  7.     protected void onCreate(Bundle savedInstanceState) {
  8.         super.onCreate(savedInstanceState);
  9.         setContentView(R.layout.activity_login);
  10.         initView();
  11.         mvc_model = new MVC_Model();//初始化Model
  12.     }
  13.     private void initView() {
  14.         tv_showData = findViewById(R.id.tv_showData);
  15.         et_userName = findViewById(R.id.et_userName);
  16.         et_passWord = findViewById(R.id.et_passWord);
  17.         findViewById(R.id.btn_login).setOnClickListener(this);//注册事件
  18.     }
  19.     @Override
  20.     public void onClick(View v) {
  21.         mvc_model.loginRequest(getLoginData(), new OnLoginCallback() {//业务代码
  22.             @Override
  23.             public void onSuccess(LoginBean loginBean) {
  24.                 tv_showData.setText("登录成功:" + loginBean.toString());//设置数据
  25.             }
  26.             @Override
  27.             public void onError() {
  28.                 tv_showData.setText("登录失败,账号密码错误!");//设置数据
  29.             }
  30.         });
  31.     }
  32.     //获取登录数据
  33.     public LoginBean getLoginData() {
  34.         String userName = et_userName.getText().toString();
  35.         String passWord = et_passWord.getText().toString();
  36.         return new LoginBean(userName, passWord);
  37.     }
  38. }
复制代码
 我们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 没有厘革
  1. public class MVP_Model {
  2.     private SQLUtils sqlUtils;
  3.     public MVP_Model(){
  4.         sqlUtils = new SQLUtils();
  5.     }
  6.     //登录请求
  7.     public void loginRequest(LoginBean loginBean, OnLoginCallback loginCallback) {
  8.         if (sqlUtils.queryUserName().equals(loginBean.getUserName()) &&
  9.                 sqlUtils.queryPassWord().equals(loginBean.getPassWord())) {
  10.             //登录成功
  11.             loginCallback.onSuccess(loginBean);
  12.         } else {
  13.             //登录失败
  14.             loginCallback.onError();
  15.         }
  16.     }
  17. }
复制代码
 MVP_View
  1. public interface MVP_View extends OnLoginCallback{
  2.     LoginBean getLoginData();
  3. }
复制代码

 接下来我们来看看Presenter怎样来调和 MVP_View 与 MVP_Model 的
  1. public class MVP_Presenter {
  2.     private MVP_View mvp_view;
  3.     private MVP_Model mvp_model;
  4.     public MVP_Presenter(MVP_View mvp_view) {
  5.         this.mvp_view = mvp_view;//view接口由Activity那边传递
  6.         this.mvp_model = new MVP_Model();//model在Presenter内创建
  7.     }
  8.     public void loginRequest(LoginBean loginBean) {
  9.         mvp_model.loginRequest(loginBean, new OnLoginCallback() {
  10.             public void onSuccess(LoginBean loginBean1) {
  11.                 mvp_view.onSuccess(loginBean1);//反馈成功数据
  12.             }
  13.             public void onError() {
  14.                 mvp_view.onError();//反馈失败
  15.             }
  16.         });
  17.     }
  18. }
复制代码
 我们来看看图解:

 接下来我们来看看 业务代码与逻辑代码都被解耦了,那Activity尚有什么事呢?
  1. //实现 MVP_View 接口重写 getLoginData、onSuccess、onError、进行获取数据与数据更新
  2. public class MVP_Activity extends AppCompatActivity
  3. implements View.OnClickListener, MVP_View {
  4.     private TextView tv_showData;
  5.     public EditText et_userName;
  6.     public EditText et_passWord;
  7.     private MVP_Presenter mvp_presenter;
  8.     @Override
  9.     protected void onCreate(Bundle savedInstanceState) {
  10.         super.onCreate(savedInstanceState);
  11.         setContentView(R.layout.activity_login);
  12.         initView();
  13.         mvp_presenter = new MVP_Presenter(this);
  14.     }
  15.     private void initView() {
  16.         tv_showData = findViewById(R.id.tv_showData);
  17.         et_userName = findViewById(R.id.et_userName);
  18.         et_passWord = findViewById(R.id.et_passWord);
  19.         findViewById(R.id.btn_login).setOnClickListener(this);
  20.     }
  21.     @Override
  22.     public void onClick(View v) {
  23.         mvp_presenter.loginRequest(getLoginData());//请求登录
  24.     }
  25.     @Override
  26.     public LoginBean getLoginData() {
  27.         String userName = et_userName.getText().toString();
  28.         String passWord = et_passWord.getText().toString();
  29.         return new LoginBean(userName, passWord);
  30.     }
  31.     @SuppressLint("SetTextI18n")
  32.     @Override
  33.     public void onSuccess(LoginBean MVVMLoginBean) {
  34.         tv_showData.setText("登录成功:" + MVVMLoginBean.toString());
  35.     }
  36.     @Override
  37.     public void onError() {
  38.         tv_showData.setText("登录失败,账号密码错误!");
  39.     }
  40. }
复制代码

这张图解是不是发现大多数都是界面代码没发现有逻辑代码了,由于逻辑代码已经被解耦到 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

  1. public class MVVM_Model {
  2.     private SQLUtils sqlUtils;
  3.     public MVVM_Model(){
  4.         sqlUtils = new SQLUtils();
  5.     }
  6.     //登录请求
  7.     public void loginRequest(LoginBean loginBean, OnLoginCallback loginCallback) {
  8.         if (sqlUtils.queryUserName().equals(loginBean.getUserName()) &&
  9.                 sqlUtils.queryPassWord().equals(loginBean.getPassWord())) {
  10.             //登录成功
  11.             loginCallback.onSuccess(loginBean);
  12.         } else {
  13.             //登录失败
  14.             loginCallback.onError();
  15.         }
  16.     }
  17. }
复制代码
 我们再来看看 ViewModel 是怎样与View相互绑定的
ViewModel

  1. public class MVVM_ViewModel extends BaseObservable {
  2.     private MVVM_Model mvvm_model;
  3.     private String result;
  4.     private ActivityMvvmBinding binding;
  5.     //该方法由View界面自动调用
  6.     @Bindable
  7.     public String getResult() {
  8.         return result;
  9.     }
  10.     //设置结果到View界面并刷新
  11.     public void setResult(String result) {
  12.         this.result = result;
  13.         notifyPropertyChanged(BR.result);
  14.     }
  15.     //构造方法初始化
  16.     public MVVM_ViewModel(ActivityMvvmBinding binding) {
  17.         mvvm_model = new MVVM_Model();
  18.         this.binding = binding;
  19.     }
  20.     //通过binding获取数据
  21.     public LoginBean getLoginBean() {
  22.         return new LoginBean(
  23.                 binding.etUserName.getText().toString()
  24.                 , binding.etPassWord.getText().toString()
  25.         );
  26.     }
  27.     //View界面注册的单击事件
  28.     public void loginRequest(View view) {
  29.         mvvm_model.loginRequest(getLoginBean(), new OnLoginCallback() {
  30.             @Override
  31.             public void onSuccess(LoginBean loginBean) {
  32.                 setResult("获取成功:" + loginBean.toString());
  33.             }
  34.             @Override
  35.             public void onError() {
  36.                 setResult("获取失败:账号或密码错误!");
  37.             }
  38.         });
  39.     }
  40. }
复制代码
 我们来图解一下:图有点大,但放大看还是看的很透彻的

 看完这张图你应该可以明确,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














免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?立即注册

x

帖子地址: 

回复

使用道具 举报

分享
推广
火星云矿 | 预约S19Pro,享500抵1000!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

草根技术分享(草根吧)是全球知名中文IT技术交流平台,创建于2021年,包含原创博客、精品问答、职业培训、技术社区、资源下载等产品服务,提供原创、优质、完整内容的专业IT技术开发社区。
  • 官方手机版

  • 微信公众号

  • 商务合作