android MVP模式介绍与实战
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模式介绍与实战的更多相关文章
- Android MVP模式 简单易懂的介绍方式
		
主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200
 - Android MVP模式简单易懂的介绍方式 (三)
		
Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 讲完M和P,接下来就要讲V了.View ...
 - Android MVP模式简单易懂的介绍方式 (二)
		
Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 上一篇文章我们介绍完了Model的创建 ...
 - Android MVP模式简单易懂的介绍方式 (一)
		
Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...
 - Android MVP模式
		
转自http://segmentfault.com/blogs,转载请注明出处Android MVP Pattern Android MVP模式\[1\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...
 - android MVP模式简单介绍
		
原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/ 前言 MVP作为一种MVC的演化版本在Android开发中受到 ...
 - Android MVP模式简单介绍:以一个登陆流程为例
		
老的项目用的MVC的模式,最近完成了全部重构成MVP模式的工作,虽然比较麻烦,好处是代码逻辑更加清楚.简洁,流程更加清晰,对于后续版本迭代维护都挺方便.对于一些想要学习MVP模式的同学来讲,百度搜出来 ...
 - Android mvp模式、mvvm模式
		
MVC和MVP的区别2007年08月08日 星期三 上午 09:23 MVC和MVP到底有什么区别呢? 从这幅图可以看到,我们可以看到在MVC里,View是可以直接访问Model的!从而,View里会 ...
 - Android MVP模式 谷歌官方代码解读
		
Google官方MVP Sample代码解读 关于Android程序的构架, 当前(2016.10)最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法. Repo ...
 
随机推荐
- ODAC (V9.5.15) 学习笔记(二十一)数据复制
			
用TVirtualTable在内存中缓存TOraQuery中的数据,主要应用场景是参照其他数据,需要将TOraQuery中的数据复制到TVirtualTable,由于没有类似于TClientDataS ...
 - 安卓开发笔记——自定义HorizontalScrollView控件(实现QQ5.0侧滑效果)
			
对于滑动菜单栏SlidingMenu,大家应该都不陌生,在市场上的一些APP应用里经常可以见到,比如人人网,FaceBook等. 前段时间QQ5.0版本出来后也采用了这种设计风格:(下面是效果图) 之 ...
 - 详解shape标签
			
转载自:http://blog.csdn.net/harvic880925/article/details/41850723 一.简单使用 刚开始,就先不讲一堆标签的意义及用法,先简单看看shape标 ...
 - Haskell 与范畴论
			
说到 Haskell,这真是一门逼格极高的编程语言,一般初学者如果没有相关函数式编程的经验,入门直接接触那些稀奇古怪的概念,简直要跪下.现在回想起来,隐隐觉得初学者所拥有的命令式编程语言(impera ...
 - Ip 地址
			
访问 ip.mayfirst.org可以显示你的ip地址,如果你可以联网的话.
 - 蓝凌OA二次开发手册
			
1.蓝凌OA表单前端调用后台数据 一.后台存储过程: create procedure sp_test @ftext nvarchar(50) as begin select @ftext as '测 ...
 - php中关于js保存文件至本地的问题
			
最近在搞一个livezilla的在线客服聊天的东东,客户界面要求添加一个下载聊天记录的功能.于是我就是翻看了下网上的各种关于”js保存文件至本地“的资料,发现只能在IE下通过execCommand实现 ...
 - Lua中的require
			
lua中的require机制 为了方便代码管理,通常会把lua代码分成不同的模块,然后在通过require函数把它们加载进来.现在看看lua的require的处理流程.1.require机制相关 ...
 - http--响应请求状态码
			
针对客户端向Web服务器发送的任意一个HTTP请求,不论在何种情况下得到一个响应,每个响应均具有一个由3位数字表示的状态码和相应的描述文字.不同数值的状态码体现了不同类型的响应状态,W3C对响应状态码 ...
 - [IR] Probabilistic Model
			
If user has told us some relevant and some irrelevant documents, then we can proceed to build a prob ...