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

  1. /**
  2. * *Created by su on 2016/6/22.
  3. */
  4. public interface OperationView {
  5. void showCreatingPhone();
  6. void showPhoneCountChange();
  7. void showNoPhone();
  8. void showFactoryBusy();
  9. void showCreatedPhone();
  10. }

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

  1. public class MainActivity extends AppCompatActivity implements OperationView {
  2. private ListView listView;
  3. private Button btnCreate;
  4. private PhonePresenter phonePresenter;
  5. private ProgressDialog mLoadingDialog;
  6. ArrayAdapter<Phone> arrayAdapter;
  7. private Toast toast;
  8. @Override
  9. protected void onCreate(Bundle savedInstanceState) {
  10. super.onCreate(savedInstanceState);
  11. setContentView(R.layout.activity_main);
  12. Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
  13. setSupportActionBar(toolbar);
  14. PhoneFactory phoneFactory = new PhoneFactory();
  15. phoneFactory.createPhone("nokia",555);
  16. phonePresenter = new PhonePresenter(phoneFactory, this);
  17. btnCreate = (Button) findViewById(R.id.btnCreate);
  18. listView = (ListView) findViewById(R.id.listView);
  19. arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, phoneFactory.getPhonesList());
  20. btnCreate.setOnClickListener(new View.OnClickListener() {
  21. @Override
  22. public void onClick(View v) {
  23. phonePresenter.addPhone(new Phone("iphone", 4000+ new Random().nextInt(1000)));
  24. }
  25. });
  26. listView.setAdapter(arrayAdapter);
  27. listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
  28. @Override
  29. public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
  30. phonePresenter.removePhone(position);
  31. }
  32. });
  33. }
  34. @Override
  35. public void showCreatingPhone() {
  36. mLoadingDialog = new ProgressDialog(this);
  37. mLoadingDialog.setProgressStyle(ProgressDialog.STYLE_SPINNER);
  38. mLoadingDialog.setMessage("工厂正在生产手机");
  39. mLoadingDialog.setCancelable(true);
  40. mLoadingDialog.show();
  41. }
  42. @Override
  43. public void showPhoneCountChange() {
  44. arrayAdapter.notifyDataSetChanged();
  45. }
  46. @Override
  47. public void showNoPhone() {
  48. findViewById(R.id.noPhone).setVisibility(View.VISIBLE);
  49. }
  50. @Override
  51. public void showFactoryBusy() {
  52. showToast("工厂繁忙,请稍后再试!");
  53. }
  54. @Override
  55. public void showCreatedPhone() {
  56. if (mLoadingDialog != null && mLoadingDialog.isShowing()) {
  57. mLoadingDialog.dismiss();
  58. }
  59. mLoadingDialog = null;
  60. showToast("新生产出一台手机!");
  61. findViewById(R.id.noPhone).setVisibility(View.GONE);
  62. }
  63. private void showToast(String string) {
  64. if (toast == null) {
  65. toast = Toast.makeText(this, string, Toast.LENGTH_SHORT);
  66. }else{
  67. toast.setText(string);
  68. }
  69. toast.show();
  70. }
  71. }

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

  1. /**
  2. * Created by su on 2016/6/22.
  3. */
  4. /**
  5. * 手机工厂类
  6. */
  7. public class PhoneFactory {
  8. private ArrayList<Phone> phonesList = new ArrayList<>();
  9. public void addPhone(Phone phone) {
  10. phonesList.add(phone);
  11. }
  12. public void removePhone(Phone phone) {
  13. phonesList.remove(phone);
  14. }
  15. public void removePhone(int index) {
  16. if (index >= 0 && index < phonesList.size()) {
  17. phonesList.remove(index);
  18. }
  19. }
  20. public void createPhone(String name, double price) {
  21. Phone phone = new Phone(name, price);
  22. phonesList.add(phone);
  23. }
  24. public ArrayList<Phone> getPhonesList() {
  25. return phonesList;
  26. }
  27. public int getPhoneCounts() {
  28. return phonesList.size();
  29. }
  30. }

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

  1. public class PhonePresenter implements TaskPresenter{
  2. private final PhoneFactory phoneFactory;
  3. private final OperationView operationView;
  4. private static final long createPhoneTime = 2000;
  5. private static final int msgWhat = 0x102;
  6. public PhonePresenter(@NonNull PhoneFactory phoneFactory, @NonNull OperationView operationView) {
  7. this.phoneFactory = phoneFactory;
  8. this.operationView = operationView;
  9. }
  10. @Override
  11. public void addPhone(Phone phone) {
  12. operationView.showPhoneCountChange();
  13. if (mHandler.hasMessages(msgWhat)) {
  14. operationView.showFactoryBusy();
  15. return;
  16. }
  17. Message message = new Message();
  18. message.what = msgWhat;
  19. message.obj = phone;
  20. mHandler.sendMessageDelayed(message, createPhoneTime);
  21. operationView.showCreatingPhone();
  22. }
  23. @Override
  24. public void removePhone(int index) {
  25. phoneFactory.removePhone(index);
  26. if (phoneFactory.getPhoneCounts() <= 0) {
  27. operationView.showNoPhone();
  28. }
  29. operationView.showPhoneCountChange();
  30. }
  31. @Override
  32. public void removePhone(Phone phone) {
  33. }
  34. public ArrayList<Phone> getPhones() {
  35. ArrayList<Phone> phones = phoneFactory.getPhonesList();
  36. if (phones.isEmpty()) {
  37. operationView.showNoPhone();
  38. }
  39. return phones;
  40. }
  41. private Handler mHandler = new Handler() {
  42. @Override
  43. public void handleMessage(Message msg) {
  44. super.handleMessage(msg);
  45. phoneFactory.addPhone((Phone)msg.obj);
  46. operationView.showCreatedPhone();
  47. operationView.showPhoneCountChange();
  48. }
  49. };
  50. }

运行效果图如下:

总结

使用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. Inventory of the materials to teach you how to query a date certain combination of dimensions

    Please correct me if any omission or error From the Inventory Management-> journals-> Item Cou ...

  2. WCF中因序列化问题引起的异常和错误。

    尝试对参数 http://tempuri.org/ 进行序列化时出错: parameters.InnerException 消息是“不应为数据协定名称为“DBNull:http://schemas.d ...

  3. Subgradient Algorithm

    Subgradient是一种可以优化不可微的凸函数的方法. 首先回顾凸函数的定义: $f(y) \geq f(x) + \nabla f(x)^T(y-x), all \hspace{2 pt} x, ...

  4. Ubuntu中QT使用FFmpeg的奇怪问题

    FFmpeg都已经编译安装好了,QT的程序中调用av_register_all却总是在链接阶段报错,经过长时间的摸索,发现时静态链接库的问题,网上给出的答案都只能解决部分问题,所需的全部链接库如下: ...

  5. EFW框架源代码版本升级记录说明

    回<[开源]EFW框架系列文章索引>        EFW框架源代码下载V1.3:http://pan.baidu.com/s/1c0dADO0 EFW框架实例源代码下载:http://p ...

  6. android手机出现sqlite3 not found的解决方法

    解决方法如下: 1.如果/system目录为不可读写的,需要挂载为读写: C:\Users\easteq>adb shell root@android:/ # mount -o remount, ...

  7. 挑选分组中top1

    select * from( select *, ROW_NUMBER() over(partition by accountid order by opentime DESC) as rowNumf ...

  8. 页面头部title、description、keywords标签的优化

    页面头部优化<Head></Head>中间的区域中间的区域,我们称为网页的头部.在网页的头部中,通常存放一些介绍页面内容的信息,例如页面标题.描述及关键字等等.在头部优化中,除 ...

  9. Lua中的weak表——weak table

    弱表(weak table)是一个很有意思的东西,像C++/Java等语言是没有的.弱表的定义是:A weak table is a table whose elements are weak ref ...

  10. eclipse开发web应用程序步骤(图解)

    *运行环境(也就是服务器的选择) 环境搭建好之后开始编写web程序!然后右键->Run as -> Run on Server!