初识MVP
学习Android有一段时间了,一直以实现一些小功能的方式来学习。这样就导致了代码写的不怎么规范,以至于后来重新翻看自己的代码并且重构自己的项目的时候,被自己的代码恶心到了。
以至于后来学习了一些设计模式,以及架构工程的设计模式才得以改进。
话不多说,下面谈谈我学习MVP的过程以及我对MVP的理解。
谈及MVP,许多人都会先从MVC讲起。我认为这是很有必要的,因为MVP架构,就是因为MVC在Android无法更好解决问题的时候才提出的。那么什么是MVC,MVC有什么优缺点,为什么MVC在大型的Andorid项目中暴露出那么多缺点呢?
带着这几个问题,下面先来从新认识一下MVC架构
1、什么是MVC?
关于什么是MVC,网上有很多资料,我这里也不班门弄斧,简单的给大家进行介绍。
MVC即Model-View-Controller。M:逻辑模型,V:视图模型,C:控制器
逻辑模型(Model)
所谓逻辑模型,通俗的理解就是指业务逻辑层,同时对数据的操作的层,比如网络中请求一些数据、数据库中存取等
视图模型(View)
视图层,望文即可生义,视图层就是可以理解为展示给用户的界面,其中包括一系列View组件、布局、按钮等等。
控制层(Controller)
控制层是MVC中相对比较重要的一层,它负责协调M-V两层,在Android中,Activity就是一个典型的Controller,它即可响应View的事件,也可调用Model中的数据和方法,进而反馈到View层中
所以,MVC中,基本的流程就是,M负责数据的来源和处理,然后通过C将数据反馈到V。
2、MVC有什么优点?
MVC对于传统的应用是有着巨大的帮助与贡献的,为什么这么说?因为,在传统的应用中,MVC三层的划分可以让工程划分的更分析,同时,这样也可以实现层次间的解耦,以及提升开发的效率。在开发的过程中,只要相互间约定好接口,就可以各自开发而且互相之间不会有什么冲突。
另外,MVC的另一个优点就是简单。由于它的简单性,就可以让开发人员迅速掌握,并且很好的运用到工程中。
3.MVC为何在大型Android项目中会显得有点不太“适用”?
MVC在Android这个“特殊”的环境中有时会显得有点力不从心甚至还会出现拖后腿的现象。
在Android中,Activity通常就充当一个Controller的角色,但Activity还具有操作View的责任、响应View的事件以及响应自身生命周期的责任。这样一来,使得一个Activity的代码数量很容易上千甚至上万,如此一来,Activity就变得非常臃肿,变得不好维护和阅读。除此以外,C-V之间耦合度也就高了,甚至可以说是M和V重合在一起了。
基于上面的几个问题,我们就可以引出
MVP模式
看了上面几个问题,你可能会认为MVP的出现可能大概就是为了填MVC所挖的坑的吧。
MVP其实就是MVC的“进化版”,和MVC一样,MV都分别代表Model和View层,Presenter则是表示层。
下面用两个图来表示
上面可以看出,MVC中允许Model和View中进行交互,而在MVP中,把Layout布局和Activity作为View层,增加了Presenter层,利用Presenter和Model层进行业务交互,然后Presenter再与View层交互,从而避免了View与Modele之间相互联系的现象。出现这样的根本原因在于Presenter的出现让Activity的工作量减轻了不少,它把Controller的工作从Activity身上切了出来。
上面分析了一下MVP,接下来就是实现MVP的一个Demo
实现一个简单的登陆功能,包结构如下
1.准备一个User的实体类
package com.example.mvp.mvp.bean;
public class User {
private String username ;
private String password ;
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
2.Model层
model层需要一个接口以及它的实现类
package com.example.mvp.mvp.model;
import com.example.mvp.mvp.bean.User;
public interface IUserBiz {
void login(String username,String password,OnLoginListener loginListener);
interface OnLoginListener {
void loginSuccess(User user);
void loginFailed();
}
}
3.View层
View层只有一个接口
package com.example.mvp.mvp.view;
import com.example.mvp.mvp.bean.User;
public interface IUserLoginView {
String getUserName();
String getPassword();
void clearPassword();
void clearUserName();
void showLoading();
void hideLoading();
void toMainActivity(User user);
void showFailedError();
}
4.Presenter层
presenter层有一个实体类
package com.example.mvp.mvp.presenter;
import android.os.Handler;
import com.example.mvp.mvp.bean.User;
import com.example.mvp.mvp.model.IUserBiz;
import com.example.mvp.mvp.model.OnLoginListener;
import com.example.mvp.mvp.model.UserBiz;
import com.example.mvp.mvp.view.IUserLoginView;
public class UserLoginPresenter {
private IUserBiz userBiz;//model层引用
private IUserLoginView userLoginView;//View层引用
private Handler mHandler = new Handler();
public UserLoginPresenter(IUserLoginView userLoginView){
this.userLoginView = userLoginView;
this.userBiz = new UserBiz();
}
public void login(){
userLoginView.showLoading();
//模拟数据加载时的线程切换(View的操作需要放在主线程)
userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() {
@Override
public void loginSuccess(final User user) {
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.toMainActivity(user);
userLoginView.hideLoading();
}
});
}
@Override
public void loginFailed() {
mHandler.post(new Runnable() {
@Override
public void run() {
userLoginView.showFailedError();
userLoginView.hideLoading();
}
});
}
});
}
public void clear(){
userLoginView.clearUserName();
userLoginView.clearPassword();
}
}
5.Activity
package com.example.mvp.mvp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.Toast;
import com.example.mvp.R;
import com.example.mvp.mvp.bean.User;
import com.example.mvp.mvp.presenter.UserLoginPresenter;
import com.example.mvp.mvp.view.IUserLoginView;
public class LoginActivity extends AppCompatActivity implements IUserLoginView{
private EditText mEtUsername, mEtPassword;
private Button mBtnLogin, mBtnClear;
private ProgressBar mPbLoading;
private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this);
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
initView();
}
private void initView(){
mEtUsername = (EditText) findViewById(R.id.et_userName);
mEtPassword = (EditText) findViewById(R.id.et_password);
mBtnClear = (Button) findViewById(R.id.bt_clear);
mBtnLogin = (Button) findViewById(R.id.bt_login);
mPbLoading = (ProgressBar) findViewById(R.id.progress);
mBtnLogin.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
mUserLoginPresenter.login();
}
});
mBtnClear.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
mUserLoginPresenter.clear();
}
});
}
@Override
public String getUserName()
{
return mEtUsername.getText().toString();
}
@Override
public String getPassword()
{
return mEtPassword.getText().toString();
}
@Override
public void clearUserName()
{
mEtUsername.setText("");
}
@Override
public void clearPassword()
{
mEtPassword.setText("");
}
@Override
public void showLoading()
{
mPbLoading.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading()
{
mPbLoading.setVisibility(View.GONE);
}
@Override
public void toMainActivity(User user) {
Toast.makeText(this, user.getUsername() +
" login success , to MainActivity", Toast.LENGTH_SHORT).show();
}
@Override
public void showFailedError() {
Toast.makeText(this,
"login failed", Toast.LENGTH_SHORT).show();
}
}
分析、总结
由上面的代码大概可以看出MVP的基本思想,正如前面所说,MVP的出现是淡化了Activity在安卓中充当Controller这一角色的事实,更多的是把Activity归属到View层中,使得Activity的工作变得更轻松。当然,如果相对于小型的项目,Activity完全可以充当Controller的作用,因为在小型的项目中,Activity处理的东西会相对较少,此时用上MVP的架构可能会将一件简单的事情复杂化。
说明:上述代码是借鉴鸿洋大神的《浅谈 MVP in Android》一文完成,如有错误,敬请指出,谢谢。