Android的MVP模式讲解
程序员文章站
2024-03-15 18:50:12
...
UI层越来越复杂,为了减轻了UI层的责任,也是为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数 据的可视化以及与用户的交互,让Model只关系数据的处理,MVP(Model-View-Presenter)模式应运而生。每个人对MVP模式都有一定的理解,此篇仅供参考交流。
(1)View:负责绘制UI元素、与用户进行交互(View interface与Presenter进行交互,降低耦合);(2)Model:依然是业务逻辑和实体模型、操纵数据(有时也实现一个Model interface用来降低耦合);
(3)Presenter:作为View与Model交互的中间纽带,负责完成View于Model间的交互(处理与用户交互的负责逻辑)
项目Demo结构图:
(1)首先我们需要一个Bean
public class LoginUserBean {
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)View的接口,需要用到的方法:
public interface LoginView {
void clearUsername();
void clearPassword();
void setUsernameError();
void setPasswordError();
void navigateToHome();
}
(3)LoginActivity实现View接口
public class LoginActivity extends Activity implements LoginView,OnClickListener {
private ProgressBar progressBar;
private EditText username;
private EditText password;
private Button btn_login;
private LoginPresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
progressBar = (ProgressBar) findViewById(R.id.progress);
username = (EditText) findViewById(R.id.username);
password = (EditText) findViewById(R.id.password);
btn_login=(Button) findViewById(R.id.button);
btn_login.setOnClickListener(this);
presenter = new LoginPresenterImpl(this);
}
@Override
public void onClick(View v) {
presenter.validateCredentials(username.getText().toString(), password.getText().toString());
}
@Override
public void navigateToHome() {
//登录成功,跳转主页
//Intent intent=new Intent(this,MainActivity.class);
//startActivity(intent);
Toast.makeText(this,"成功,跳转",Toast.LENGTH_SHORT).show();
}
@Override
public void clearUsername() {
username.setText("");
}
@Override
public void clearPassword() {
password.setText("");
}
@Override
public void setUsernameError() {
username.setError(getString(R.string.username_error));
}
@Override
public void setPasswordError() {
password.setError(getString(R.string.password_error));
}
@Override
protected void onDestroy() {
presenter.onDestroy();
super.onDestroy();
}
}
(4)Model接口:
public interface LoginModel {
void login(String username, String password, OnLoginFinishedListener listener);
}
(5)Model接口的实现类:
public class LoginModelImpl implements LoginModel{
@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener) {
new Handler().postDelayed(new Runnable() {
//模拟耗时登录
@Override
public void run() {
//此处判断用户密码
if (TextUtils.isEmpty(username)){
listener.onUsernameError();//model层里面回调listener
}
if (TextUtils.isEmpty(password)){
listener.onPasswordError();
}
//此处成功,(真实应该网络返回成功,这里省略)
//调用回调方法,通过LoginPresenter操作ui层,跳转到主页
listener.onSuccess();
}
}, 2000);
}
}
(6)Presenter桥梁接口:
public interface LoginPresenter {
void validateCredentials(String username, String password);
void onDestroy();
}
(7)Presenter现实类,实现回调OnLoginFinishedListener,M层通过回调方法操作Ui层:
public class LoginPresenterImpl implements LoginPresenter, OnLoginFinishedListener {
private LoginView loginView;
private LoginModel loginModel;
public LoginPresenterImpl(LoginView loginView) {
this.loginView = loginView;
this.loginModel = new LoginModelImpl();
}
//ui层调用
@Override
public void validateCredentials(String username, String password) {
loginModel.login(username, password, this);
}
@Override
public void onSuccess() {
if (loginView != null) {
//M层回调后,这里操作Ui层接口的跳转
loginView.navigateToHome();
}
}
@Override
public void onDestroy() {
loginView = null;
}
@Override
public void onUsernameError() {
if (loginView != null) {
loginView.setUsernameError();
loginView.clearUsername();
}
}
@Override
public void onPasswordError() {
if (loginView != null) {
loginView.setPasswordError();
loginView.clearPassword();
}
}
@Override
public void clearUsername() {
// TODO Auto-generated method stub
}
@Override
public void clearPassword() {
// TODO Auto-generated method stub
}
}
(8)回调接口:
public interface OnLoginFinishedListener {
void clearUsername();
void clearPassword();
void onUsernameError();
void onPasswordError();
void onSuccess();
}
登录流程解析:
1-首先是点击了按钮,在Ui层LoginActivity调用桥梁实现类LoginPresenterImpl的方法validateCredentials()
@Override
public void onClick(View v) {
presenter.validateCredentials(username.getText().toString(), password.getText().toString());
}
2-LoginPresenterImpl类操作M层
@Override
public void validateCredentials(String username, String password) {
loginModel.login(username, password, this);
}
3-LoginModelImpl中的login,当后台数据返回成功时,调用回调方法操作LoginPresenterImpl类onSuccess方法,
这里onSuccess方法中loginView.navigateToHome()就是操作UI层,达到跳转主页.
@Override
public void login(final String username, final String password, final OnLoginFinishedListener listener) {
new Handler().postDelayed(new Runnable() {
//模拟耗时登录
@Override
public void run() {
//此处判断用户密码
if (TextUtils.isEmpty(username)){
listener.onUsernameError();//model层里面回调listener
}
if (TextUtils.isEmpty(password)){
listener.onPasswordError();
}
//此处成功,(真实应该网络返回成功,这里省略)
//调用回调方法,通过LoginPresenter操作ui层,跳转到主页
listener.onSuccess();
}
}, 2000);
}
4-loginView.navigateToHome()方法操作的UI层如下:
@Override
public void navigateToHome() {
//登录成功,跳转主页
//Intent intent=new Intent(this,MainActivity.class);
//startActivity(intent);
Toast.makeText(this,"成功,跳转",Toast.LENGTH_SHORT).show();
}
总结:通过上面流程可以看出,View只负责处理与用户进行交互,并把数据相关的逻辑操作都扔给了Presenter去做。而Presenter调用Model处理完数据之后,再通过IUserView更新View显示的信息。每个人对MVP模式都有一定的理解,此篇仅供参考交流。