android MVP模式介绍与实战

描述


MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。

MVC和MVP的区别?


为什么会出现MVP模式呢?这是因为原有的MVC模式有一些短板。比如在android开发中,activity充当着MVC中Controller的角色,但是在实际开发中处理view的逻辑和角色。当业务界面复杂时我的activity会显得很庞大。于是出现了MVP模式,它新增了一个Presenter角色用于处理数据和界面的模型以及逻辑,Activity仅仅用于展示界面和用户交互,这样就解决了MVC中角色不清的局面。

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

在MVC里,View是可以直接访问Model的!从而,View里会包含Model信息,不可避免的还要包括一些业务逻辑。 在MVC模型里,更关注的Model的不变,而同时有多个对Model的不同显示,即View。所以,在MVC模型里,Model不依赖于View,但是View是依赖于Model的。不仅如此,因为有一些业务逻辑在View里实现了,导致要更改View也是比较困难的,至少那些业务逻辑是无法重用的。

MVC模式结构

  • Model 业务逻辑和实体模型
  • Controller 对应Activity
  • View 视图以及布局文件

MVP模式结构

  • Model: 业务逻辑和实体模型
  • View:用户交互和视图显示,在android中对应activity
  • Presenter: 负责完成View于Model间的逻辑和交互

小节:MVP模式相当于在MVC模式中又加了一个Presenter用于处理模型和逻辑,将View和Model完全独立开,在android开发中的体现就是activity仅用于显示界面和交互,activity不参与模型结构和逻辑,

实战

谷歌官网给了我们一个MVP模式实战的例子,它是一个类似记事本的app,源码地址在:https://github.com/googlesamples/android-architecture

官方案例的框架图如下:

看完源码后发现其不适合初学者理解,于是我自己写了一个demo方便大家理解。

demo源码地址:https://github.com/halibobo/AndroidMvpExample

源码主要类的结构如下

下面来看源码

View层对应的是MainActivity,它继承了抽离出View所有操作方法的接口OperationView

/**
* *Created by su on 2016/6/22.
*/
public interface OperationView { void showCreatingPhone(); void showPhoneCountChange(); void showNoPhone(); void showFactoryBusy(); void showCreatedPhone();
}

MainActivity具体对每个操作进行了具体的实现

    public class MainActivity extends AppCompatActivity implements OperationView {

    private ListView listView;

    private Button btnCreate;

    private PhonePresenter phonePresenter;

    private ProgressDialog mLoadingDialog;
ArrayAdapter<Phone> arrayAdapter;
private Toast toast;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar); PhoneFactory phoneFactory = new PhoneFactory();
phoneFactory.createPhone("nokia",555);
phonePresenter = new PhonePresenter(phoneFactory, this);
btnCreate = (Button) findViewById(R.id.btnCreate);
listView = (ListView) findViewById(R.id.listView);
arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, phoneFactory.getPhonesList());
btnCreate.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
phonePresenter.addPhone(new Phone("iphone", 4000+ new Random().nextInt(1000)));
}
}); listView.setAdapter(arrayAdapter); listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
phonePresenter.removePhone(position);
}
}); } @Override
public void showCreatingPhone() {
mLoadingDialog = new ProgressDialog(this);
mLoadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
mLoadingDialog.setMessage("工厂正在生产手机");
mLoadingDialog.setCancelable(true);
mLoadingDialog.show();
} @Override
public void showPhoneCountChange() {
arrayAdapter.notifyDataSetChanged();
} @Override
public void showNoPhone() {
findViewById(R.id.noPhone).setVisibility(View.VISIBLE);
} @Override
public void showFactoryBusy() {
showToast("工厂繁忙,请稍后再试!");
} @Override
public void showCreatedPhone() {
if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
mLoadingDialog.dismiss();
}
mLoadingDialog = null;
showToast("新生产出一台手机!");
findViewById(R.id.noPhone).setVisibility(View.GONE);
} private void showToast(String string) {
if (toast == null) {
toast = Toast.makeText(this, string, Toast.LENGTH_SHORT);
}else{
toast.setText(string);
}
toast.show();
}
}

Model层对应的是PhoneFactory,它处理和数据相关的一些简单操作

	 /**
* Created by su on 2016/6/22.
*/ /**
* 手机工厂类
*/ public class PhoneFactory {
private ArrayList<Phone> phonesList = new ArrayList<>(); public void addPhone(Phone phone) {
phonesList.add(phone);
} public void removePhone(Phone phone) {
phonesList.remove(phone);
} public void removePhone(int index) {
if (index >= 0 && index < phonesList.size()) {
phonesList.remove(index);
}
} public void createPhone(String name, double price) {
Phone phone = new Phone(name, price);
phonesList.add(phone);
} public ArrayList<Phone> getPhonesList() {
return phonesList;
} public int getPhoneCounts() {
return phonesList.size();
}
}

下面是最为重要的Presenter层 对应代码中的PhonePresenter,它处理界面逻辑和数据模型等,源码如下:

public class PhonePresenter implements TaskPresenter{

    private final PhoneFactory phoneFactory;
private final OperationView operationView; private static final long createPhoneTime = 2000;
private static final int msgWhat = 0x102; public PhonePresenter(@NonNull PhoneFactory phoneFactory, @NonNull OperationView operationView) {
this.phoneFactory = phoneFactory;
this.operationView = operationView;
} @Override
public void addPhone(Phone phone) {
operationView.showPhoneCountChange();
if (mHandler.hasMessages(msgWhat)) {
operationView.showFactoryBusy();
return;
}
Message message = new Message();
message.what = msgWhat;
message.obj = phone;
mHandler.sendMessageDelayed(message, createPhoneTime);
operationView.showCreatingPhone();
} @Override
public void removePhone(int index) {
phoneFactory.removePhone(index);
if (phoneFactory.getPhoneCounts() <= 0) {
operationView.showNoPhone();
}
operationView.showPhoneCountChange();
} @Override
public void removePhone(Phone phone) { } public ArrayList<Phone> getPhones() {
ArrayList<Phone> phones = phoneFactory.getPhonesList();
if (phones.isEmpty()) {
operationView.showNoPhone();
}
return phones;
} private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
phoneFactory.addPhone((Phone)msg.obj);
operationView.showCreatedPhone();
operationView.showPhoneCountChange();
}
};
}

运行效果图如下:

总结

使用MVP模式会使得代码多出一些接口但是使得代码逻辑更加清晰,尤其是在处理复杂界面和逻辑时,我们可以对同一个activity将每一个业务都抽离成一个Presenter,这样代码既清晰逻辑明确又方便我们扩展。当然如果我们的业务逻辑本身就比较简单的话使用MVP模式就显得,没那么必要。所以我们不需要为了用它而用它,具体的还是要要业务需要

谢谢大家

demo地址在:https://github.com/halibobo/AndroidMvpExample

android MVP模式介绍与实战的更多相关文章

  1. Android MVP模式 简单易懂的介绍方式

    主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200

  2. Android MVP模式简单易懂的介绍方式 (三)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 讲完M和P,接下来就要讲V了.View ...

  3. Android MVP模式简单易懂的介绍方式 (二)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 上一篇文章我们介绍完了Model的创建 ...

  4. Android MVP模式简单易懂的介绍方式 (一)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...

  5. Android MVP模式

    转自http://segmentfault.com/blogs,转载请注明出处Android MVP Pattern Android MVP模式\[1\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...

  6. android MVP模式简单介绍

    原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/ 前言 MVP作为一种MVC的演化版本在Android开发中受到 ...

  7. Android MVP模式简单介绍:以一个登陆流程为例

    老的项目用的MVC的模式,最近完成了全部重构成MVP模式的工作,虽然比较麻烦,好处是代码逻辑更加清楚.简洁,流程更加清晰,对于后续版本迭代维护都挺方便.对于一些想要学习MVP模式的同学来讲,百度搜出来 ...

  8. Android mvp模式、mvvm模式

    MVC和MVP的区别2007年08月08日 星期三 上午 09:23 MVC和MVP到底有什么区别呢? 从这幅图可以看到,我们可以看到在MVC里,View是可以直接访问Model的!从而,View里会 ...

  9. Android MVP模式 谷歌官方代码解读

    Google官方MVP Sample代码解读 关于Android程序的构架, 当前(2016.10)最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法. Repo ...

随机推荐

  1. Codeforces Round #184 (Div. 2) E. Playing with String(博弈)

    题目大意 两个人轮流在一个字符串上删掉一个字符,没有字符可删的人输掉游戏 删字符的规则如下: 1. 每次从一个字符串中选取一个字符,它是一个长度至少为 3 的奇回文串的中心 2. 删掉该字符,同时,他 ...

  2. 强(strong)、软(soft)、弱(weak)、虚(phantom)引用

    https://github.com/Androooid/treasure/blob/master/source/lightsky/posts/mat_usage.md 1.1 GC Root JAV ...

  3. 【转】基于CXF Java 搭建Web Service (Restful Web Service与基于SOAP的Web Service混合方案)

    转载:http://www.cnblogs.com/windwithlife/archive/2013/03/03/2942157.html 一,选择一个合适的,Web开发环境: 我选择的是Eclip ...

  4. 利用SVN工具下载OpenCore代码

    OpenCore原来使用的是CVS管理代码的.从09年起,更换用SVN管理代码,大家可以用TortoiseSVN软件下载代码,网址是:http://tortoisesvn.net/,安装后tortoi ...

  5. bash的一些小技巧

    1.从输入读入变量 eg:read -ep "input yes or no: " flag 用e选项表示编辑,可以使用backspace删除 2.数组 a.索引数组 declar ...

  6. WWDC2015 结束.新一波更新以及bug即将来袭.

    WWDC结束.新一波更新以及bug即将来袭. HTTPS 将成为标准链接. http被报错. GamePlayKit 这是搞那样. 还有ReplayKit  那些什么录像分享什么的还有活路么? Mod ...

  7. JavaScript之Array常用函数汇总

    [20141121]JavaScript之Array常用功能汇总 *:first-child { margin-top: 0 !important; } body>*:last-child { ...

  8. 用户授权 OAuth 2.0

    什么是OAuth OAuth是一个关于授权(Authorization)的开放网络标准,目前的版本是2.0版.OAuth适用于各种各样的包括提供用户身份验证机制的应用程序,注意是Authorizati ...

  9. OpenGL开发环境配置-Windows/MinGW/Clion/CMake

    因为某些原因,不想用过于臃肿的VS了,转而使用常用的jetbrains的CLion,Clion沿袭了jetbrans的优良传统,基本代码提示功能还是比较好的,不过就是对于windows不熟悉cmake ...

  10. EPANET中读取INPUT文件的函数文件——INPUT1.C/INPUT2.C/INPUT3.C

    首先介绍下这3个文件的关系:可以说INPUT1.C的函数粒度最大,它的函数getdata()就完成了整个INPUT文件数据的读入,该函数又调用了INPUT2.C中的部分函数,INPUT2.C文件中的函 ...