IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发测试 -> Android 架构MVC MVP MVVM+实例 -> 正文阅读

[开发测试]Android 架构MVC MVP MVVM+实例

前言

????????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创建一个布局文件

????<!--缩减版-->
????<LinearLayout
????????...>
????????<EditText
????????????android:id="@+id/et_account"
????????????.../>
????</LinearLayout>
????<LinearLayout
????????...>
????????<EditText
????????????android:id="@+id/et_password"
????????????.../>
????</LinearLayout>
????<Button
????????android:id="@+id/btn_login"
????????.../>
????<Button
????????android:id="@+id/btn_back"
????????.../>

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。

<?xml?version="1.0"?encoding="utf-8"?>
<layout?xmlns:android="http://schemas.android.com/apk/res/android">

????<data>
????????<!--为引入的类从新起一个变量名,方便下面使用-->
????????<variable
????????????name="loginViewModel"
????????????type="com.scc.architecture.mvvm.viewmodel.LoginViewModel"?/>
????</data>
????<LinearLayout
????????...>
????????<LinearLayout
????????????...>
????????????<EditText
????????????????android:id="@+id/et_account"
????????????????...
????????????????android:text="@={loginViewModel.user.name}"?/>
????????</LinearLayout>

????????<LinearLayout
????????????...>
????????????<EditText
????????????????android:id="@+id/et_password"
????????????????...
????????????????android:text="@={loginViewModel.user.password}"?/>
????????</LinearLayout>

????????<Button
????????????android:id="@+id/btn_login"
????????????...
????????????android:onClick="login"
????????????android:text="@string/str_login"?/>

????????<Button
????????????android:id="@+id/btn_back"
????????????...
????????????android:onClick="back"
????????????android:text="@string/str_back"?/>
????</LinearLayout>
</layout>

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和实例基本写完了,但是感觉自己理解的不是很好,有大佬能指点就更好了。最后,希望对你有借鉴意义。

实例传送门

  开发测试 最新文章
pytest系列——allure之生成测试报告(Wind
某大厂软件测试岗一面笔试题+二面问答题面试
iperf 学习笔记
关于Python中使用selenium八大定位方法
【软件测试】为什么提升不了?8年测试总结再
软件测试复习
PHP笔记-Smarty模板引擎的使用
C++Test使用入门
【Java】单元测试
Net core 3.x 获取客户端地址
上一篇文章           查看所有文章
加:2021-08-20 15:25:05  更:2021-08-20 15:26:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/19 8:39:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码