Android开发模式MVP,MVC

来源:互联网 发布:centos 集成环境 编辑:程序博客网 时间:2024/06/06 10:38
一、概述
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来处理逻辑    
MVC模式:
1)、View可以与Model直接交互
2)、Controller是基于行为的,并且可以被多个View共享
3)、可以负责决定显示哪个View


使用MVP模式的好处:
1)、分离了视图逻辑和业务逻辑,降低了耦合:随着界面及其逻辑的复杂度不断提升,Activity类的 职责不断增加,以致变得庞大臃肿
2)、模块职责划分明显:View,Presenter,Model
3)、Presenter被抽象成接口,可以有多种具体的实现,所以方便进行单元测试
    4)、Activity只处理生命周期的任务,代码变得更加简洁
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用来承载数据和对登陆数据判断
   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
原创粉丝点击