http://www.cnblogs.com/wanqieddy/p/4478690.html
上面有个例子,重点参考
http://www.cnblogs.com/mybkn/archive/2012/04/12/2443676.html
http://www.cnblogs.com/cqumonk/p/4392285.html
目录
一、MVP的介绍
二、为什么要用MVP
三、MVP与MVC的不同
四、利用MVP进行Android开发的例子
一、MVP的介绍
随着UI创建技术的功能越来越强,UI层也履行着越来越多的职责。为了更好的细分视图(View)与模型(Model)的功能,让View更专注于数据的可视化
和与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP模式产生了。
MVP有下面的四个要素:
1.View:负责绘制UI元素,与用户进行交互,在Android中体现为Activity。
2.View interface:需要View实现的接口,View通过View interface 与 Presenter进行交互,降低耦合,方便进行单元测试。
3.Model: 负责存储,检索,操纵数据(有时也实现 一个Model interface用来降低耦合)。
4.Presenter:作为View 与 Model交互的中间纽带,处理与用户交互的逻辑。
如下图
二、为什么要用MVP
随着界面和逻辑的复杂度不断提升,Activity类的职责越来越重。因此我们将其中复杂的逻辑处理移到另外的一个类(Presenter)中时,Activit其实就是MVP
中的View ,它负责UI元素的初始化,建立UI元素与Presenter的关系(Listener之类),同时自己也会处理一些简单的逻辑(复杂的逻辑交由Presenter处理)。
另外,回想一下我们在开发android应用的时候,都是怎么对代码 逻辑进行测试的?每次我们都要将应用安装到android真机上,然后通过用户操作进行测试,
这浪费了我们大量的时间。而在MVP模式中,处理复杂逻辑的Presenter是通过 interface 与 View(Activity)进行交互的,所以我们可以通过自定义类实现这个
interface来模拟Activity 的行为对 Presenter进行单元测试,节省了大量的测试时间。
三、MVP与MVC的不同
MVP
- View 不直接与Model进行交互,而是通过与 Presenter 交互来与Model 间接交互。
- Presenter 与View的交互是通过接口来实现 的,利于添加单元测试。
- 通常View 与 Presenter 是一对一的,但复杂的View可以有多个 Presenter 。
MVC
- View可以与Model直接交互。
- Controller 是基于行为的,并且可以被多个View共享 。
- 可以负责决定显示哪个View
四、利用MVP进行Android开发的例子
首先是目录结构
可以看到Model与 View都是通过 interface与Presenter进行交互的,这样降低了耦合,还降低了测试的难度。
- 定义一个UserBean来保存用户信息
package com.chuiyuan.bean; public class UserBean { private String firstName ; private String lastName ; public UserBean (String firstName , String lastName ){ this.firstName = firstName ; this.lastName = lastName ; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; } }
- View接口
由需求可以知道,View可以对ID ,firstname ,lastname这三个 EditText进行读操作,对firstname ,lastname 还可以进行写操作,由此我们定义接口如下
public interface IUserView { int getID(); String getLastName () ; String getFirstName (); void setFirstName (String firstName ); void setLastName (String lastName ) ; }
- Model接口
同样,Model也要对这三个字段进行读写操作,并存储在某个载体内(这时我们暂时不关心,可以是内存,文件,数据结构等,但对于Presenter和View没有
影响),定义 IUserModel的接口
public interface IUserModel { void setID(int id ) ; void setFirstName(String firstName ); void setLastName (String lastName); UserBean load(int id ) ;//通过id读取信息 }
- Model功能的实现
public class UserModel implements IUserModel { private String mFristName; private String mLastName; private int mID; private SparseArray<UserBean> mUsererArray = new SparseArray<UserBean>(); @Override public void setID(int id) { // TODO Auto-generated method stub mID = id; } @Override public void setFirstName(String firstName) { // TODO Auto-generated method stub mFristName = firstName; } @Override public void setLastName(String lastName) { // TODO Auto-generated method stub mLastName = lastName; UserBean UserBean = new UserBean(mFristName, mLastName); mUsererArray.append(mID, UserBean); } @Override public UserBean load(int id) { // TODO Auto-generated method stub mID = id; UserBean userBean = mUsererArray.get(mID, new UserBean("not found", "not found")); return userBean; } }
- Presenter
这时,Presenter就可以通过接口与Model/View进行交互了。
public class UserPresenter { private IUserView mUserView ; private IUserModel mUserModel ; public UserPresenter (IUserView view){ mUserView = view ; mUserModel = new UserModel(); } public void saveUser (int id, String firstName ,String lastName ){ mUserModel.setID(id) ; mUserModel.setFirstName(firstName) ; mUserModel.setLastName(lastName) ; } public void loadUser (int id ){ //加载并更新显示 UserBean user = mUserModel.load(id) ; mUserView.setFirstName(user.getFirstName()) ; mUserView.setLastName(user.getLastName()) ; } }
- UserViewActivity
UserViewActivity实现了IUserView及View.OnClickListener接口,同时有一个UserPresenter成员变量.
package com.chuiyuan.view; import com.chuiyuan.presenter.UserPresenter; import com.example.mvptest.R; import com.example.mvptest.R.id; import com.example.mvptest.R.layout; import android.R.integer; import android.support.v7.app.ActionBarActivity; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.EditText; public class UserViewActivity extends ActionBarActivity implements OnClickListener, IUserView { private EditText mFirstNameEt , mLastNameEt, mIdEt ; private Button mSaveBtn ,mLoadBtn ; private UserPresenter mUserPresenter ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); findWidget(); mUserPresenter = new UserPresenter(this ) ; mSaveBtn.setOnClickListener(this ) ; mLoadBtn.setOnClickListener(this ); } private void findWidget() { mFirstNameEt = (EditText)findViewById(R.id.first_name_edt); mLastNameEt = (EditText)findViewById(R.id.last_name_edt) ; mIdEt = (EditText)findViewById(R.id.id_edt ) ; mSaveBtn = (Button)findViewById(R.id.saveButton) ; mLoadBtn= (Button)findViewById(R.id.loadButton) ; } @Override public int getID() { // TODO Auto-generated method stub return Integer.parseInt(mIdEt.getText().toString()); } @Override public String getLastName() { // TODO Auto-generated method stub return mLastNameEt.getText().toString(); } @Override public String getFirstName() { // TODO Auto-generated method stub return mFirstNameEt.getText().toString(); } @Override public void setFirstName(String firstName) { mFirstNameEt.setText(firstName) ; } @Override public void setLastName(String lastName) { mLastNameEt.setText(lastName) ; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.saveButton: mUserPresenter.saveUser(getID(), getFirstName(), getLastName()) ; break; case R.id.loadButton: mUserPresenter.loadUser(getID()) ; break ; default: break; } } }
可以看到,View只负责处理与用户的交互,而将数据相关的逻辑都交给了Presenter去做,而Presenter调用Model处理完数据后,而通过IUserView更新
View的显示的消息。
整体结构如下