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. 图解 & 深入浅出 JavaWeb:Servlet 再说几句

    Writer      :BYSocket(泥沙砖瓦浆木匠) 微         博:BYSocket 豆         瓣:BYSocket FaceBook:BYSocket Twitter   ...

  2. Eplan转载

    引言:标准化工程设计理念成功实施后之后,清晰透明的管理流程将水到渠成,过往繁复无比的流程得以简化,管理与被管理者皆愿欣然承受. 市场竞争日趋激烈的今天,对用户需求.市场的快速响应,尽量地控制成本是企业 ...

  3. redis的主从复制部署和使用

    reids一种key-value的缓存数据库目前非常流行的被使用在很多场景,比如在数据库读写遇到瓶颈时缓存且读写分离会大大提升这块的性能,下面我就说说redis的主从复制 首先需要启动多个redis实 ...

  4. Flash Media Server 4.5 序列号 (fms4.5 激活码)

    激活码一枚   ,网上找不到的..我今天放出来了哦... 1462-5864-7783-6034-8316-3718    (亲测 可用) 安装前找到系统盘下windows/system32/driv ...

  5. 储物柜soket通信协议和中间件实现技术细节

    一.中间件程序的职责: 1)对柜机提供soket长连接的服务器端,就是soket server.可提供上万的客户端同时连接.用来实时响应控制请求,中间件必须随时知道某个柜机的在线状态,外部请求时才能判 ...

  6. Raspberry Pi --操作LED

    最简单的一个树莓派GPIO操作入门,这里记录以下 先上连接图: 卧槽.图真特么的大 用到了GPIO的GND和#18针脚,这就不上图了,红色的线接的是18针脚,暗色的线接的是GND针脚,下面上Pytho ...

  7. Struts2知多少(2) Struts2 是什么

    Struts2是流行和成熟的基于MVC设计模式的Web应用程序框架. Struts2不只是Struts1下一个版本,它是一个完全重写的Struts架构. WebWork框架开始以Struts框架为基础 ...

  8. 白话Redis与Memcached区别

    如果简单地比较Redis与Memcached的区别,外在的区别是: 1  Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,zset,hash等数据结构的存储. 2  Redis ...

  9. MySQL不能插入中文字符及中文字符乱码问题

    MySQL的默认编码是Latin1,不支持中文,要支持中午需要把数据库的默认编码修改为gbk或者utf8.在安装后MySQL之后,它的配置文件不是很给力,不知道你们的是不是,反正我的是! 开始插入中文 ...

  10. WCF小白初试 错误之一:“有零个应用程序终结点”的解决办法

    遇到这类问题 应该是配置文件出现了问题 解决办法是将配置文件中的<service name="命名空间+类名">就可以解决