来源:http://blog.csdn.net/p106786860/article/details/53439421
相关阅读:
吊炸天!74款APP完整源码!
2016年未,腾讯,百度,华为,搜狗和滴滴Android面试题汇总
一直以来,想分享MVP的实战,因为很多项目开始并不是就是mvp架构的,可能是从传统的mvc结构变迁过来的。今天呈详给大家分享的这篇从mvc重构到mvp,让大家既能看到前后的对比,又能突出mvp的优点。
一、MVC
1.简介
MVC是目前大多数企业采用J2EE的结构设计,主要适用于交互式的Web应用。在Android中也有体现和使用,但是存在一定的弊端(下面将讲述),于是才有了Android官方推荐的MVP。
View层:
activity_login.xml
LoginInputView.java
Model层:
LoginModel.java
public interface LoginModel {
LoginResult loginByUserNameAndPassword(Context context, LoginParam loginParam);
}
LoginModelImp.java
public interface LoginModel {
LoginResult loginByUserNameAndPassword(Context context, LoginParam loginParam);
}
Controller层:
LoginActivity.java
public class LoginActivity extends AppCompatActivity implements View.OnClickListener {
//View层渲染用户登录页面 组件
private LoginInputView userNameInput;
private LoginInputView passWordInput;
private Button loginButton;
private TextView responseTextView;
//Modle层提封装了登录请求数据和行为
private LoginModel loginModel;
private Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
//Controller层获取Modle更新变化,选择到合适的视图更新显示
Bundle bundle = msg.getData();
LoginResult loginResult = (LoginResult) bundle.getSerializable("result");
responseTextView.setText(loginResult.getMessage());
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
userNameInput = (LoginInputView) findViewById(R.id.login_intput_username);
passWordInput = (LoginInputView) findViewById(R.id.login_intput_password);
loginButton = (Button) findViewById(R.id.login_login_button);
responseTextView = (TextView) findViewById(R.id.login_result_text);
loginButton.setOnClickListener(this);
userNameInput.setTitle("UserName:");
passWordInput.setTitle("PassWord:");
loginModel = new LoginModelImp();
}
@Override
public void onClick(View v) {
//接受从View层获取的用户点击,分发到Controller处理
responseTextView.setText("");
//Controller层从View层选择视图,获取用户输入
final String userName = userNameInput.getContent();
final String passWorld = passWordInput.getContent();
new Thread(new Runnable() {
@Override
public void run() {
//Controller层将用户输入登录信息,发送到Model层执行登录相关逻辑
LoginParam loginParam = new LoginParam(userName,passWorld);
LoginResult loginResult = loginModel.loginByUserNameAndPassword(LoginActivity.this,loginParam);
//Model层获取登录信息后,通知Controller层更新UI
Message message = handler.obtainMessage();
message.what = 1;
Bundle bundle = new Bundle();
bundle.putSerializable("result", loginResult);
message.setData(bundle);
handler.sendMessage(message);
}
}).start();
}
}
运行结果:
3.优点
Controller层起到桥梁作用,在View层和Model层之间通信,使得View层和Modle层分离解耦;
4.缺点
然而,在Android中由于View层的XML控制太弱,Controler层的Activity并没有和View层完全分离。当需要动态改变一个页面的显示(如背景、显示隐藏按钮等),都无法在xml中处理,只能在Activity中处理。造成了Activity即时Controller层又是View层,代码繁冗。
二、MVP
1.简介
MVP模式是MVC模式在Android上的一种变体。在MVC中Activity应该是属于Controller层,而实质上,它即承担了Contrller,也包含了许多View层的逻辑在里面。把Activity中的UI逻辑抽象成View接口,把业务逻辑抽象成Presenter接口,Model类还是原来的Model,这就是MVP;
Model层:同MVC,负责处理数据加载或者存储,如从网络或者数据库获取数据等;
View层:处理数据展示,用户的交互。在MVP中Activity,Fragment属于该层;
Presenter层:是Model层和View层的桥梁,从Model层中获取数据,展示在View层;
2.实践
项目结构:
Model层:同上mvc
View层:同上mvc,但activity在mvp中为view层,重构如下:
public class LoginActivity extends AppCompatActivity implements View.OnClickListener, LoginContract.View {
private LoginInputView userNameInput;
private LoginInputView passWordInput;
private Button loginButton;
private TextView responseTextView;
private Handler handler = new LoginHander();
private LoginContract.Presenter loginPesenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
userNameInput = (LoginInputView) findViewById(R.id.login_intput_username);
passWordInput = (LoginInputView) findViewById(R.id.login_intput_password);
loginButton = (Button) findViewById(R.id.login_login_button);
responseTextView = (TextView) findViewById(R.id.login_result_text);
loginPesenter = new LoginPresenter(new LoginModelImp(), this);
}
@Override
protected void onResume() {
super.onResume();
loginPesenter.start();
}
@Override
public void onClick(View v) {
loginPesenter.doLoginRequest(LoginActivity.this);
}
@Override
public void setPresenter(LoginContract.Presenter presenter) {
loginPesenter = presenter;
}
@Override
public void initLoginShow() {
userNameInput.setTitle("UserName:");
passWordInput.setTitle("PassWord:");
loginButton.setOnClickListener(this);
}
@Override
public LoginParam getInputLoginParam() {
final String userName = userNameInput.getContent();
final String passWorld = passWordInput.getContent();
LoginParam loginParam = new LoginParam(userName, passWorld);
return loginParam;
}
@Override
public void sendShowLoginMessage(LoginResult loginResult) {
Message message = handler.obtainMessage();
message.what = 1;
Bundle bundle = new Bundle();
bundle.putSerializable("result", loginResult);
message.setData(bundle);
handler.sendMessage(message);
}
@Override
public void updateLoginResultByMessage(Message message) {
Bundle bundle = message.getData();
LoginResult loginResult = (LoginResult) bundle.getSerializable("result");
updateLoginResultByString(loginResult.getMessage());
}
@Override
public void updateLoginResultByString(String result) {
responseTextView.setText(result);
}
/**
* 登录Handler,处理来自子线程更新登录页面的消息
*/
private class LoginHander extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
updateLoginResultByMessage(msg);
break;
}
}
}
}
Presenter层:
BasePresenter.java
public interface BasePresenter {
void start();
}
BaseView.java
public interface BaseView {
void setPresenter(T presenter);
}
LoginContract.java
public interface LoginContract {
interface View extends BaseViewPresenter> {
/**
* 初始化登录页面显示
*/
void initLoginShow();
/**
* 获取输入的登录参数
*/
LoginParam getInputLoginParam();
/**
* 发送显示登录结果消息
*/
void sendShowLoginMessage(LoginResult loginResult);
/**
* 通过消息更新登录结果
*/
void updateLoginResultByMessage(Message message);
/**
* 更新登录结果信息
*/
void updateLoginResultByString(String s);
}
interface Presenter extends BasePresenter {
/**
* 执行登录请求
*/
void doLoginRequest(Context context);
}
}
LoginPresenter.java
public class LoginPresenter implements LoginContract.Presenter {
private final LoginModel loginModel;
private final LoginContract.View loginView;
public LoginPresenter(LoginModel loginModel, LoginContract.View loginView) {
this.loginModel = loginModel;
this.loginView = loginView;
loginView.setPresenter(this);
}
@Override
public void start() {
loginView.initLoginShow();
}
@Override
public void doLoginRequest(final Context context) {
loginView.updateLoginResultByString("");
new Thread(new Runnable() {
@Override
public void run() {
LoginParam loginParam = loginView.getInputLoginParam();
LoginResult loginResult = loginModel.loginByUserNameAndPassword(context, loginParam);
loginView.sendShowLoginMessage(loginResult);
}
}).start();
}
}
关于Java和Android大牛频道
Java和Android大牛频道是一个数万人关注的探讨Java和Android开发的公众号,分享和原创最有价值的干货文章,让你成为这方面的大牛!
我们探讨android和Java开发最前沿的技术:android性能优化 ,插件化,跨平台,动态化,加固和反破解等,也讨论设计模式/软件架构等。由一群来自BAT的工程师组成的团队。
关注即送红包,回复:“百度” 、“阿里”、“腾讯” 有惊喜!!!关注后可用入微信群。群里都是来自百度阿里腾讯的大牛。
欢迎关注我们,一起讨论技术,扫描和长按下方的二维码可快速关注我们。或搜索微信公众号:JANiubility。
公众号:JANiubility