您的位置:首页 > 移动开发 > Android开发

Android开发模式MVP,MVC

2016-12-27 21:48 465 查看
一、概述

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;
}

@Override
public String getName(
4000
) {
return name;
}

@Override
public String getPasswd() {
return passwd;
}

@Override
public 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());
}
@Override
public void clear() {
iLoginView.onClearText();
}

@Override
public 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() {
@Override
public void run() {
iLoginView.onLoginResult(result, code);
}
}, 5000);

}

@Override
public 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下载地址:点击下载源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息