android架构MVP模式

背景

为啥需要有MVP模式?根本在于我们的Activity太重了,承担的功能过于复杂,不符合软件开发高内聚低耦合的要求,所以需要我们可以仿照网页开发MVC模式,将传统的Activity一分为二,将视图和控制视图逻辑抽离出来,也就是这里的View和Presenter,当然Model还是保持一致的。
当View与Model解耦后就不一样了,因为View并不知道Model的存在,我们可以直接对Model进行单元测试,无需依赖 Android 的环境。同理当我们进行 UI 测试时,可以通过 Mock 测试用数据来检查V层是否可以正常显示,而无需依赖后台!
android架构MVP模式_第1张图片

实现

MVP实现总的原则就是,将传统中Activity中的操作都抽象成接口View与Presenter互相持有彼此对象,通过接口进行通信。这句话看上去挺抽象的,下面通过代码来详细介绍。
这里最具代表的例子,用户登录功能。首先我们建立view接口和presenter接口。
view接口中,需要展示登录,展示重置登录两个功能:

public interface LoginView{
	void onClear();
	void onLogin(boolean result, int code);
}

presenter接口中,就要有view对应展示的逻辑:

public interface LoginPresenter {
	void doclear();
	void doLogin(String name, String passwd);
}

这种写法会导致我们要创建大量的接口文件,Google 推荐我们的做法是使用 Contract 类来管理接口:

public interface ContractLogin{

	public interface LoginView{
		void onClear();
		void onLogin(boolean result, int code);
	}
	public interface LoginPresenter {
		void doclear();
		void doLogin(String name, String passwd);
	}
}

那么回到之前的问题,如何让“View与Presenter互相持有彼此对象,通过接口进行通信”。通过在presenter的实现类中,将view注入,实现presenter的方法时回调view中定义的方法:

public class LoginPresenterImpl implements ContractLogin.LoginPresenter{
	private ContractLogin.LoginView mView;//在presenter实现类中持有view,并将其注入
	public LoginPresenterImpl(ContractLogin.LoginView mView){
		this.mView=mView;
	}
	
	@Override
	public void doclear() {
		//回调view中的方法
		mView.onClearText();
	}

	@Override
	public void doLogin(String name, String passwd) {
		boolean isLoginSuccess = true;
		final int code = check(name,passwd);//这里比对数据库中和用户输入的是否一致
		if (code!=0) 
			isLoginSuccess = false;
		final boolean result = isLoginSuccess;
		//回调view中的方法
		mView.onLogin(result,code);
	}
}

至此,presenter完成了对view的持有,下面让Activity去实现View,让View持有presenter对象:

public class LoginActivity extends AppCompatActivity implements ContractLogin.LoginView , View.OnClickListener{
	private ContractLogin.LoginPresenter mPresenter;//在View中实现类中持有presenter,并将其注入
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_login);

		//初始化控件
		EditText acount = (EditText) this.findViewById(R.id.login_username);//账户
		EditText Pass = (EditText) this.findViewById(R.id.login_password);//密码
		Button btnLogin = (Button) this.findViewById(R.id.btn_login_login);//登录按钮
		Button btnClear = (Button) this.findViewById(R.id.btn_login_clear);//重置按钮


		//设置监听
		btnLogin.setOnClickListener(this);
		btnClear.setOnClickListener(this);

		//注入presenter
		loginPresenter = new LoginPresenterCompl(this);
	}
		@Override
		public void onClick(View v) {
			switch (v.getId()){
				case R.id.btn_login_clear:
					loginPresenter.doclear();
					break;
				case R.id.btn_login_login:
					loginPresenter.doLogin(editUser.getText().toString(), editPass.getText().toString());
					break;
			}
		}
	
		//实现View中定义的方法,当用户重置账号密码时在此回调view方法
		@Override
		public void onClear() {
			editUser.setText("");
			editPass.setText("");
		}
	
		@Override
		public void onLoginResult(boolean result, int code) {
			if (result){
				Toast.makeText(this,"haha",Toast.LENGTH_SHORT).show();
			}
			else
				Toast.makeText(this,"wuwu " + code,Toast.LENGTH_SHORT).show();
		}
}

至此,我们完成了view和presenter的互相持有,对应开图中双向箭头。
android架构MVP模式_第2张图片
综上这就是最简单的mvp框架的实现。

总结

优点:

  • 降低耦合度,实现了 Model 和 View 真正的完全分离,可以修改 View 而不影响 Modle;
  • 模块职责划分明显,层次清晰;
  • Presenter 可以复用,一个 Presenter 可以用于多个 View,而不需要更改 Presenter 的逻辑;
  • 利于测试驱动开发,以前的 Android 开发是难以进行单元测试的;
  • View 可以进行组件化,在 MVP 当中,View 不依赖 Model。

缺点:

  • Presenter 中除了应用逻辑以外,还有大量的 View->Model,Model->View 的手动同步逻辑,造成 Presenter 比较笨重,维护起来会比较困难;
  • 由于对视图的渲染放在了 Presenter 中,所以视图和 Presenter 的交互会过于频繁;
  • 如果 Presenter 过多地渲染了视图,往往会使得它与特定的视图的联系过于紧密,一旦视图需要变更,那么 Presenter 也需要变更了。

你可能感兴趣的:(android学习)