Android 架构MVC MVP MVVM+实例 您所在的位置:网站首页 安卓开发mvc和mvp Android 架构MVC MVP MVVM+实例

Android 架构MVC MVP MVVM+实例

2023-04-03 15:29| 来源: 网络整理| 查看: 265

这是我参与8月更文挑战的第8天,活动详情查看:8月更文挑战

前言

MVC,MVP和MVVM是软件比较常用的三种软件架构,这三种架构的目的都是分离,避免将过多的逻辑全部堆积在一个类中。

在Android中,Activity中既有UI的相关处理逻辑,又有数据获取逻辑,从而导致Activity逻辑复杂不单一难以维护。

为了一个应用可以更好的维护和扩展,我们需要很好的区分相关层级,要不然以后将数据获取方式从数据库变为网络获取时,我们需要去修改整个Activity。架构使得View和数据相互独立,我们把应用分成三个不同层级,这样我们就能够单独测试相关层级,使用架构能够把大多数逻辑从Activity中移除,方便进行单元测试。

MVC是什么?

MVC是模型(Model)-视图(View)-控制器(Controller)的缩写,用一种业务逻辑、数据、界面显示分离的方法组织代码。其实Android Studio创建一个项目的模式就是一个简化的mvc模式。

Android中的MVC含义 Model:实体类(数据的获取、存储、数据状态变化)。 View:布局文件 Controller:Activity(处理数据、业务和UI)。 工作原理

1.View接受用户的交互请求。 2.View将请求转交给Controller。 3.Controller操作Model进行数据更新。 4.数据更新之后,Model通知View数据变化。 5.View显示更新之后的数据。 MVC的缺点

随着界面及其逻辑的复杂度不断提升,Activity类的职责不断增加,以致变得庞大臃肿。

为了解决MVC的缺点,MVP 框架被提出来。

MVP是什么

MVP是MVC架构的一个演化版,全称是Model-View-Presenter。将MVC中的V和C结合生成MVP中的V,引入新的伙伴Presenter。

Android中的MVP含义 Model:实体类(数据的获取、存储、数据状态变化)。 View:布局文件+Activity。 Presenter:中介,负责完成View与Model间的交互和业务逻辑。 工作原理

1.View 接收用户交互请求 2.View 将请求转交给 Presenter(V调用P接口) 3.Presenter 操作Model进行数据更新(P调用M接口) 4.Model 通知Presenter数据发生变化(M调用P接口) 5.Presenter 更新View数据(P执行接口,V相应回调) MVP的优点 1.复杂的逻辑处理放在Presenter进行处理,减少了Activity的臃肿。 2.解耦。Model层与View层完全分离,修改V层不会影响M层,降低了耦合性。 3.可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。 4.Presenter层与View层的交互是通过接口来进行的,便于单元测试。 MVP的缺点

维护困难。Presenter中除了业务逻辑以外,还有大量的View->Model,Model->View的手动同步逻辑,造成Presenter比较笨重,维护起来会比较困难。

MVVM是什么

是 Model-View-ViewModel 的简写。MVVM与MVP的结构还是很相似的,就是将Presenter升级为ViewModel。在MVVM中,View层和Model层进行了双向绑定(即Data Binding),所以Model数据的更改会表现在View上,反之亦然。ViewModel就是用来根据具体情况处理View或Model的变化。

Android中的MVVM含义 Model:实体类(数据的获取、存储、数据状态变化)。 View:布局文件+Activity。 ViewModel: 关联层,将Model和View进行绑定,Model或View更改时,实时刷新对方。

工作原理

1.View 接收用户交互请求 2.View 将请求转交给ViewModel 3.ViewModel 操作Model数据更新 4.Model 更新完数据,通知ViewModel数据发生变化 5.ViewModel 更新View数据

View/Model的变动,只要改其中一方,另一方都能够及时更新到

MVVM的优点 1.提高可维护性。Data Binding可以实现双向的交互,使得视图和控制层之间的耦合程度进一步降低,分离更为彻底,同时减轻了Activity的压力。 2.简化测试。因为同步逻辑是交由Binder做的,View跟着Model同时变更,所以只需要保证Model的正确性,View就正确。大大减少了对View同步更新的测试。 3.ViewModle易于单元测试。 MVVM的缺点 1.对于简单的项目,使用MVVM有点大材小用。 2.对于过大的项目,数据绑定会导致内存开销大,影响性能。 3.ViewModel和View的绑定,使页面异常追踪变得不方便。有可能是View出错,也有可能是ViewModel的业务逻辑有问题,也有可能是Model的数据出错。 MVP和MVC的最大区别

在MVP中View并不直接使用Model,它们之间的通信是通过Presenter 来进行的,所有的交互都发生在Presenter内部,而在MVC中View直接从Model中读取数据而不是通过 Controller。

如何选取框架

本来是要每个模式写一个适用场景,最后想想每个人都有自己的理解,别被他人束缚了。

一句话:适合自己的才是最好的!

实例

就这么一个界面咱通过MVC、MVP、MVVM分别搭建一下。

MVC实例 代码结构

1.在layout创建一个布局文件 复制代码 2.实体类(User) public class User { private String name; private String password; public User() {} //set or get ... public User(String name, String password) { this.name = name; this.password = password; } } 复制代码 3.MVCLoginActivity //用户点击事件 mvcBinding.mcvLogin.btnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { user.setName(mvcBinding.mcvLogin.etAccount.getText().toString()); user.setPassword(mvcBinding.mcvLogin.etPassword.getText().toString()); login(user); } }); //逻辑处理 private void login(User user){ if(!user.getName().isEmpty()&&!user.getPassword().isEmpty()){ if(user.getName().equals("scc001")&&user.getPassword().equals("111111")) { Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show(); }else{ Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show(); } }else { Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show(); } } 复制代码 MVP实例 代码结构

1.Model层

实体类bean,同MVC中的User类,就不贴代码浪费大家时间了。

Model层所要执行的业务逻辑

/** * 功能:接口,表示Model层所要执行的业务逻辑 */ public interface LoginModel { //User实体类;OnLoginFinishedListener presenter业务逻辑的返回结果 void login(User user, OnLoginFinishedListener listener); } 复制代码

实现类(实现LoginModel接口)

/** * 功能:实现Model层逻辑 */ public class LoginModelImpl implements LoginModel { //第4步:验证帐号密码 @Override public void login(User user, OnLoginFinishedListener listener) { if(user.getName().isEmpty()||!user.getName().equals("scc001")){ //第5步:Model层里面回调Presenter层listener listener.onUserNameError(); }else if(user.getPassword().isEmpty()||!user.getPassword().equals("111111")){ //第5步:Model层里面回调Presenter层listener listener.onPasswordError(); }else { //第5步:Model层里面回调Presenter层listener listener.onSuccess(); } } } 复制代码 2.Presenter层

当Model层得到请求的结果,回调Presenter层,让Presenter层调用View层的接口方法。

/** * 功能:当Model层得到请求的结果,回调Presenter层,让Presenter层调用View层的接口方法。 */ public interface OnLoginFinishedListener { void onUserNameError(); void onPasswordError(); void onSuccess(); } 复制代码

完成登录的验证,以及销毁当前View。

/** * 功能:登录的Presenter的接口,实现类为LoginPresenterImpl, * 完成登录的验证,以及销毁当前View。 */ public interface LoginPresenter { //完成登录的验证 void verifyData(User user); //销毁当前View void onDestroy(); } 复制代码

Presenter实现类,引入 LoginModel(model)和LoginView(view)的引用

/** * 功能:实现类,引入 LoginModel(model)和LoginView(view)的引用 */ public class LoginPresenterImpl implements OnLoginFinishedListener, LoginPresenter { //View层接口 private LoginView loginView; //Model层接口 private LoginModel loginModel; public LoginPresenterImpl(LoginView loginView) { this.loginView = loginView; this.loginModel = new LoginModelImpl(); } //第6步:通过OnLoginFinishedListener验证结果回传到Presenter层 @Override public void onUserNameError() { if (loginView != null) { //第7步:通过loginView回传到View层 loginView.setUserNameError(); loginView.hideProgress(); } } //第6步:通过OnLoginFinishedListener验证结果回传到Presenter层 @Override public void onPasswordError() { if (loginView != null) { //第7步:通过loginView回传到View层 loginView.setPasswordError(); loginView.hideProgress(); } } //第6步:通过OnLoginFinishedListener验证结果回传到Presenter层 @Override public void onSuccess() { if (loginView != null) { //第7步:通过loginView回传到View层 loginView.success(); loginView.hideProgress(); } } @Override public void verifyData(User user) { if (loginView != null) { loginView.showProgress(); } //第3步:调用model层LoginModel接口的login()方法 loginModel.login(user,this); } @Override public void onDestroy() { loginView = null; } } 复制代码 3.View层

布局文件同MVC中的View层,就不贴代码浪费大家时间了。

Presenter与View交互是通过接口。

/** * 功能:Presenter与View交互是通过接口。 * 接口中方法的定义是根据Activity用户交互需要展示的控件确定的。 */ public interface LoginView { //login是个耗时操作,加载中(一般用ProgressBar) void showProgress(); //加载完成 void hideProgress(); //login账号失败给出提示 void setUserNameError(); //login密码失败给出提示 void setPasswordError(); //login成功 void success(); } 复制代码

MVPLoginActivity

/** * 功能:需要实现LoginView接口。 */ public class MVPLoginActivity extends AppCompatActivity implements LoginView { LoginPresenterImpl loginPresenterImpl; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { ... //创建一个Presenter对象 loginPresenterImpl = new LoginPresenterImpl(MVPLoginActivity.this); //第1步:用户点击登录 mvpBinding.mvpLogin.btnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { User user = new User(); user.setName(mvpBinding.mvpLogin.etAccount.getText().toString()); user.setPassword(mvpBinding.mvpLogin.etPassword.getText().toString()); //第2步:调用Presenter接口中的验证方法 loginPresenterImpl.verifyData(user); } }); } @Override public void showProgress() { //加载中 } @Override public void hideProgress() { //加载完成 } @Override public void setUserNameError() { //第7步:通过loginView回传到View层 //账号错误 Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show(); } @Override public void setPasswordError() { //第7步:通过loginView回传到View层 //密码错误 Toast.makeText(this,"登录失败",Toast.LENGTH_SHORT).show(); } @Override public void success() { //第7步:通过loginView回传到View层 Toast.makeText(this,"登录成功",Toast.LENGTH_SHORT).show(); //登录成功 } @Override protected void onDestroy() { super.onDestroy(); loginPresenterImpl.onDestroy(); } } 复制代码 MVVM实例

1.Model层

实体类bean,继承BaseObservable

public class User extends BaseObservable{ private String name; private String password; public User() { } //BR 的域则是通过在 get 方法上加 @Bindable 生成的 @Bindable public String getName() { return name; } public void setName(String name) { this.name = name; //刷新UI //BR 的域则是通过在 get 方法上加 @Bindable 生成的 notifyPropertyChanged(BR.name); } @Bindable public String getPassword() { return password; } public void setPassword(String password) { this.password = password; //刷新UI notifyPropertyChanged(BR.password); } public User(String name, String password) { this.name = name; this.password = password; } } 复制代码 2.ViewModel层

ViewModel类,继承自ViewModel

public class LoginViewModel extends ViewModel { public User user; public User getUser() { return user; } public void setUser(User user) { this.user = user; } public void loginResult() { if(user.getName().isEmpty()||!user.getName().equals("scc001")){ user.setName("scc005"); }else if(user.getPassword().isEmpty()||!user.getPassword().equals("111111")){ user.setName("scc004"); }else { user.setName("scc003"); } user.setPassword("111111"); Log.e("--SCC--","LoginViewModel:"+user.getName()+":"+user.getPassword()); } } 复制代码 3.View层

先看布局文件,布局文件使用了DataBinding。

复制代码

MVVMLoginActivity

public class MVVMLoginActivity extends AppCompatActivity { private LoginViewModel loginVM; ActivityMvvmBinding mvvmBinding; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); //返回activity_mvvm的实体对象 mvvmBinding = DataBindingUtil.setContentView(this, R.layout.activity_mvvm); mvvmBinding.setLifecycleOwner(this); loginVM = new LoginViewModel(); //创建数据源 User user = new User( "scc001", "111111"); //将数据源交给DataBinding loginVM.setUser(user); //设置et_account:scc001|et_password:111111 mvvmBinding.setLoginViewModel(loginVM); } public void login(View view){ loginVM.loginResult(); } public void back(View view){ finish(); } } 复制代码

写到这里MVC、MCP、MVVM和实例基本写完了,但是感觉自己理解的不是很好,有大佬能指点就更好了。最后,希望对你有借鉴意义。

实例传送门


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有