Android开发模式MVP,MVC
来源:互联网 发布:centos 集成环境 编辑:程序博客网 时间:2024/06/06 10:38
一、概述
Android MVP 模式 也不是什么新鲜的东西了,当然现在也很多的项目中会用到这个模式,这个模式适合在当项目越来越庞大、复杂,参与的研发人员越来越多的时候,它的优势就会充分显示出来。如果你在公司是自己一个或者两个开发时,我觉得使用这个MVP模式的话效果不会很明显,而且反而有时会让人感觉有点臃肿,因为它需要定义的接口和presenter会比较多,好了一起来认识下它吧。
Android MVP 模式 也不是什么新鲜的东西了,当然现在也很多的项目中会用到这个模式,这个模式适合在当项目越来越庞大、复杂,参与的研发人员越来越多的时候,它的优势就会充分显示出来。如果你在公司是自己一个或者两个开发时,我觉得使用这个MVP模式的话效果不会很明显,而且反而有时会让人感觉有点臃肿,因为它需要定义的接口和presenter会比较多,好了一起来认识下它吧。
MVP模式是由MVC模式转换过来的,在MVC模式中主要分为model,view,controller,而MVP模式主要是分为了View,Model,Presenter,二者的区别:
MVP模式:
1)、View不直接与Model交互,而是通过与Presenter交互来与Model间接交互
2)、Presenter与View的交互是通过接口来进行的,更有利于添加单元测试
3)、通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑
1)、View不直接与Model交互,而是通过与Presenter交互来与Model间接交互
2)、Presenter与View的交互是通过接口来进行的,更有利于添加单元测试
3)、通常View与Presenter是一对一的,但复杂的View可能绑定多个Presenter来处理逻辑
MVC模式:
1)、View可以与Model直接交互
2)、Controller是基于行为的,并且可以被多个View共享
3)、可以负责决定显示哪个View
1)、View可以与Model直接交互
2)、Controller是基于行为的,并且可以被多个View共享
3)、可以负责决定显示哪个View
使用MVP模式的好处:
1)、分离了视图逻辑和业务逻辑,降低了耦合:随着界面及其逻辑的复杂度不断提升,Activity类的 职责不断增加,以致变得庞大臃肿
2)、模块职责划分明显:View,Presenter,Model
3)、Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
1)、分离了视图逻辑和业务逻辑,降低了耦合:随着界面及其逻辑的复杂度不断提升,Activity类的 职责不断增加,以致变得庞大臃肿
2)、模块职责划分明显:View,Presenter,Model
3)、Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
4)、Activity只处理生命周期的任务,代码变得更加简洁
5)、视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性
6)、把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM
5)、视图逻辑和业务逻辑分别抽象到了View和Presenter的接口中去,提高代码的可阅读性
6)、把业务逻辑抽到Presenter中去,避免后台线程引用着Activity导致Activity的资源无法被系统回收从而引起内存泄露和OOM
其中最重要的有三点:
Activity 代码变得更加简洁
相信很多人阅读代码的时候,都是从Activity开始的,对着一个1000+行代码的Activity,看了都觉得难受。
使用MVP之后,Activity就能瘦身许多了,基本上只有FindView、SetListener以及Init的代码。其他的就是对Presenter的调用,还有对View接口的实现。这种情形下阅读代码就容易多了,而且你只要看Presenter的接口,就能明白这个模块都有哪些业务,很快就能定位到具体代码。Activity变得容易看懂,容易维护,以后要调整业务、删减功能也就变得简单许多。
方便进行单元测试
一般单元测试都是用来测试某些新加的业务逻辑有没有问题,如果采用传统的代码风格(习惯性上叫做MV模式,少了P),我们可能要先在Activity里写一段测试代码,测试完了再把测试代码删掉换成正式代码,这时如果发现业务有问题又得换回测试代码,咦,测试代码已经删掉了!好吧重新写吧……
MVP中,由于业务逻辑都在Presenter里,我们完全可以写一个PresenterTest的实现类继承Presenter的接口,现在只要在Activity里把Presenter的创建换成PresenterTest,就能进行单元测试了,测试完再换回来即可。万一发现还得进行测试,那就再换成PresenterTest吧。
避免 Activity 的内存泄露
Android APP 发生OOM的最大原因就是出现内存泄露造成APP的内存不够用,而造成内存泄露的两大原因之一就是Activity泄露(Activity Leak)(另一个原因是Bitmap泄露(Bitmap Leak))。
Java一个强大的功能就是其虚拟机的内存回收机制,这个功能使得Java用户在设计代码的时候,不用像C++用户那样考虑对象的回收问题。然而,Java用户总是喜欢随便写一大堆对象,然后幻想着虚拟机能帮他们处理好内存的回收工作。可是虚拟机在回收内存的时候,只会回收那些没有被引用的对象,被引用着的对象因为还可能会被调用,所以不能回收。
Activity是有生命周期的,用户随时可能切换Activity,当APP的内存不够用的时候,系统会回收处于后台的Activity的资源以避免OOM。
采用传统的MV模式,一大堆异步任务和对UI的操作都放在Activity里面,比如你可能从网络下载一张图片,在下载成功的回调里把图片加载到 Activity 的 ImageView 里面,所以异步任务保留着对Activity的引用。这样一来,即使Activity已经被切换到后台(onDestroy已经执行),这些异步任务仍然保留着对Activity实例的引用,所以系统就无法回收这个Activity实例了,结果就是Activity Leak。Android的组件中,Activity对象往往是在堆(Java Heap)里占最多内存的,所以系统会优先回收Activity对象,如果有Activity Leak,APP很容易因为内存不够而OOM。
采用MVP模式,只要在当前的Activity的onDestroy里,分离异步任务对Activity的引用,就能避免 Activity Leak。
好了,接下来我们一起来看下代码吧
二、MVP简单案例
使用MVP做一个登陆的功能,当然在项目中需要根据实际情况来封装
1、项目结构
2、model层
包含有一个实体UserModel用来承载数据和对登陆数据判断
把View层针对控件操作抽象出来一些列的接口,根据实际的需要来进行设计
3、Presenter层
在Presenter层里面,Presenter掌握着View和Model的所有接口,可以根据不同的业务逻辑通过model和view两层的接口来实现特定的功能
从代码可以看出,LoginPresenterCompl保留了ILoginView的引用,因此在LoginPresenterCompl里就可以直接进行UI操作了,而不用在Activity里完成。这里使用了ILoginView引用,而不是直接使用Activity,这样一来,如果在别的Activity里也需要用到相同的业务逻辑,就可以直接复用LoginPresenterCompl类了
三、总结
可以看到我们的Activity非常的简洁,到了这里我们的项目已经搭建完成,这样做有以下好处:
1、学习过设计模式的人都知道,这样做基本符合了单一职责原则。
2、符合单一职责原则后,导致类与类组织更清晰。
3、View层与Model层交互需要通过Presenter层进行,这样v与m层级间的耦合性降低。
4、通过这种分层处理,每一层的测试也相对简单,维护性更高。
Demo下载地址:点击下载源码
二、MVP简单案例
使用MVP做一个登陆的功能,当然在项目中需要根据实际情况来封装
1、项目结构
2、model层
包含有一个实体UserModel用来承载数据和对登陆数据判断
public class UserModel implements IUser {String name;String passwd;public UserModel(String name, String passwd) {this.name = name;this.passwd = passwd;}@Overridepublic String getName() {return name;}@Overridepublic String getPasswd() {return passwd;}@Overridepublic int checkUserValidity(String name, String passwd){if (name==null||passwd==null||!name.equals(getName())||!passwd.equals(getPasswd())){return -1;}return 0;}}2、view层
把View层针对控件操作抽象出来一些列的接口,根据实际的需要来进行设计
public interface ILoginView {public void onClearText();public void onLoginResult(Boolean result, int code);public void onSetProgressBarVisibility(int visibility);}在Activity里面实现该接口的控件操作,并且初始化Presenter,这是可以看到Activity里面没有逻辑处理,只是对UI的控件进行数据或者行为的操作,所有的动作都是有Presenter的接口来实现,这样在项目里面会极大得精简Activity的体积.
public class MainActivity extends AppCompatActivity implements ILoginView,View.OnClickListener { private EditText editUser; private EditText editPass; private Button btnLogin; private Button btnClear; ILoginPresenter loginPresenter; private ProgressBar progressBar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initView(); } private void initView() { editUser = (EditText) this.findViewById(R.id.et_login_username); editPass = (EditText) this.findViewById(R.id.et_login_password); btnLogin = (Button) this.findViewById(R.id.btn_login_login); btnClear = (Button) this.findViewById(R.id.btn_login_clear); progressBar = (ProgressBar) this.findViewById(R.id.progress_login); //set listener btnLogin.setOnClickListener(this); btnClear.setOnClickListener(this); loginPresenter = new LoginPresenterCompl(this); } @Override public void onClearText() { editUser.setText(""); editPass.setText(""); } @Override public void onLoginResult(Boolean result, int code) { loginPresenter.setProgressBarVisiblity(View.INVISIBLE); btnLogin.setEnabled(true); btnClear.setEnabled(true); if (result){ Toast.makeText(this,"登陆成功",Toast.LENGTH_SHORT).show(); } else Toast.makeText(this,"登陆失败, code = " + code,Toast.LENGTH_SHORT).show(); } @Override public void onSetProgressBarVisibility(int visibility) { progressBar.setVisibility(visibility); } @Override public void onClick(View v) { switch (v.getId()){ case R.id.btn_login_clear: loginPresenter.clear(); break; case R.id.btn_login_login: btnLogin.setEnabled(false); btnClear.setEnabled(false); loginPresenter.doLogin(editUser.getText().toString(), editPass.getText().toString()); loginPresenter.setProgressBarVisiblity(View.VISIBLE); break; } }}
3、Presenter层
在Presenter层里面,Presenter掌握着View和Model的所有接口,可以根据不同的业务逻辑通过model和view两层的接口来实现特定的功能
public interface ILoginPresenter {void clear();void doLogin(String name, String passwd);void setProgressBarVisiblity(int visiblity);}
public class LoginPresenterCompl implements ILoginPresenter {ILoginView iLoginView;IUser user;Handler handler;public LoginPresenterCompl(ILoginView iLoginView) {this.iLoginView = iLoginView;initUser();handler = new Handler(Looper.getMainLooper());}@Overridepublic void clear() {iLoginView.onClearText();}@Overridepublic void doLogin(String name, String passwd) {Boolean isLoginSuccess = true;final int code = user.checkUserValidity(name,passwd);if (code!=0) isLoginSuccess = false;final Boolean result = isLoginSuccess;handler.postDelayed(new Runnable() {@Overridepublic void run() {iLoginView.onLoginResult(result, code);}}, 5000);}@Overridepublic void setProgressBarVisiblity(int visiblity){iLoginView.onSetProgressBarVisibility(visiblity);}private void initUser(){user = new UserModel("mvp","mvp");}}
从代码可以看出,LoginPresenterCompl保留了ILoginView的引用,因此在LoginPresenterCompl里就可以直接进行UI操作了,而不用在Activity里完成。这里使用了ILoginView引用,而不是直接使用Activity,这样一来,如果在别的Activity里也需要用到相同的业务逻辑,就可以直接复用LoginPresenterCompl类了
三、总结
可以看到我们的Activity非常的简洁,到了这里我们的项目已经搭建完成,这样做有以下好处:
1、学习过设计模式的人都知道,这样做基本符合了单一职责原则。
2、符合单一职责原则后,导致类与类组织更清晰。
3、View层与Model层交互需要通过Presenter层进行,这样v与m层级间的耦合性降低。
4、通过这种分层处理,每一层的测试也相对简单,维护性更高。
Demo下载地址:点击下载源码
0 0
- Android开发模式MVP,MVC
- Android开发中的mvc、mvp、mvvp模式
- Android开发框架模式MVC、MVP使用总结
- Android——开发模式mvc和mvp
- Android MVC MVP MVVM 模式
- Android MVP开发模式
- android MVP 开发模式
- Android mvp开发模式
- Android 开发MVP模式
- Android mvp开发模式
- android mvp开发模式
- Android MVC模式与MVP模式
- Android中MVP模式、MVC模式
- 开发模式总结:MVC、MVP&MVVM
- MVC、MVP、MVVM三种开发模式
- Android框架模式之MVC与MVP
- 浅谈Android中的MVC与MVP模式
- Android MVP与MVC框架模式
- Android 自定义 ViewPager 打造千变万化的图片切换效果
- webStorm字体设置
- python 获取命令行参数
- 基于arcgis model转换CAD至SHP,实现注记到多边形字段传递
- ios 10 私有api 跳转设置页面
- Android开发模式MVP,MVC
- 函数
- 冬季练习
- ds作业(hash)
- OfficeContainer.cpp
- php复选框生成数组与mysql的交互问题
- OpenLayers3加载离线百度地图(百度迁徙底图)
- 计算机1
- 【服务器】nginx二级域名配置