推荐阅读:
Android MVC设计模式详解
Android 框架MVVM详解
Android 认识EventBus轻量级事件总线框架
Android 依赖注入库——Dagger2使用详解
MVP模式属于UI框架模式的一种,随着UI技术的功能日益丰富,View层也履行着越来越多的职责。为了更好地细分视图(View)与模型(Model)的功能,让View专注于处理数据的可视化以及与用户的交互,同时让Model只关系数据的处理,基于MVC概念的MVP(Model-View-Presenter)模式应运而生。为了更好的理解MVP,那就必须先了解MVC。了解了MVC后动手实践一个MVP的案例,然后进行总结。
因为MVP是由经典的设计模式MVC演变而来,它们的基本思想有相通之处:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
- 在MVC模型里,更关注模型层(Model)的不变。因为一个模型层(Model)可以被多个视图层(View)重用,Model不依赖于View,但是View是依赖于Model的。
- 在MVC模型里,视图层无法实现独立重用。视图层需要持有控制层Activity的引用才能进行UI引用。不仅如此,视图层(View)是可以直接访问模型层(Model)的数据,从而视图层不可避免会涉及一些业务逻辑。由于在View里实现的业务逻辑是无法被重用的,导致要更改和重用View变得比较困难。
- 由于模型操作接口的不同,视图可能需要多次调用模型才能获得足够的显示数据,不必要的频繁访问未变化数据的,也损害一定性能。
在MVP中视图层(View)不能直接访问模型层(Model),它们之间通过Presenter(Controller)来进行通信的。这一点很好的弥补了MVC的设计缺陷,使View与Model实现完全分离。View无法直接从Model中读取数据,所有的交互都发生在 Presenter层(Controller)。如下图所示:
(1)实现的功能,如下图所示。
(2)Model 层 ,代码如下
LoginModel.class 接口
public interface LoginModel {
interface OnLoginListener {
void onLoginSuccess();
void onLoginFail();
}
void loginSubmit(String username, String password, OnLoginListener listener);
}
UserInfo.class
public class UserInfo implements LoginModel{
private String age;
private String name;
private String gender;
private String hobby;
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
@Override
public void loginSubmit(final String username, final String password, final OnLoginListener listener) {
//此次Handler制造延迟3秒和回调——纯属模仿网络请求。实际开发可以替换
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (username.equals("1") && password.equals("1")) {
listener.onLoginSuccess();
} else {
listener.onLoginFail();
}
}
}, 2000);
}
}
*弹框 Dialog.class
/**
* 弹框工具类
*/
public class DialogUtil {
/**
* 显示基本Dialog
*/
public static void showSimpleDialog(Context context, String title, String message , DialogInterface.OnClickListener clickListener) {
AlertDialog.Builder builder =new AlertDialog.Builder(context);
// builder.setIcon(R.mipmap.ic_launcher);
builder.setTitle(title);
builder.setMessage(message);
//监听事件
if (clickListener != null){
builder.setPositiveButton("确认",clickListener);
}else{
builder.setPositiveButton("确认",null);
}
builder.setNegativeButton("取消",null);
//设置对话框是可取消的
builder.setCancelable(true);
AlertDialog dialog=builder.create();
dialog.show();
}
protected static ProgressDialog progressDialog;
/**
* 显示进度条
* @param context
* @param msg
*/
public static void showProgress(Context context,String msg){
if (progressDialog == null){
progressDialog = new ProgressDialog(context);
} else if (progressDialog.isShowing()){
progressDialog.dismiss();
}
progressDialog.setMessage(msg);
progressDialog.show();
}
/**
* 关闭进度条
*/
public static void dismissProgress(){
if (progressDialog != null ){
if (progressDialog.isShowing()){
progressDialog.dismiss();
}
}
}
}
(3)Presenter 层,代码如下
接口
public interface ILoginPresenter {
void loginSubmit(String username, String password);
}
实现
/**
* Created by aiyang on 2018/1/8.
* 中介者——处理视图和模型
*/
public class LoginPresentImpl implements ILoginPresenter,LoginModel.OnLoginListener {
private LoginView mView;
private LoginModel mModel;
/**
* 构造函数进行实例化
* @param mView
* @param mModel
*/
public LoginPresentImpl(LoginView mView, LoginModel mModel) {
this.mView = mView;
this.mModel = mModel;
}
/**
* 登陆方法
* @param username
* @param password
*/
@Override
public void loginSubmit(String username, String password) {
mView.showProgress();
mModel.loginSubmit(username,password,this);//在模型中通过接口分解结果,并将回调方法暴露出来,可以做到抽离开Model对View的联系。
}
@Override
public void onLoginSuccess() {
mView.loginSuccess();
}
@Override
public void onLoginFail() {
mView.loginFail();
mView.hideProgress();
}
}
(4)View 层 ,代码如下
/**
* Created by aiyang on 2018/1/8.
* UI接口
*/
public interface LoginView {
/**
* 显示进度条
*/
void showProgress();
/**
* 隐藏进度条
*/
void hideProgress();
/**
* 登录成功处理UI
*/
void loginSuccess();
/**
* 登录失败处理UI
*/
void loginFail();
}
BaseActivity.class
/**
* Created by aiyang on 2018/7/3.
*/
public abstract class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_base);
FrameLayout contentView = findViewById(R.id.view_content);
LayoutInflater.from(this).inflate(setContentView(),contentView);
init(savedInstanceState);
}
/**
* 设置布局
* @return
*/
protected abstract int setContentView();
/**
* 子类初始化
* @param savedInstanceState
*/
protected abstract void init(Bundle savedInstanceState);
/**
* 设置标题
* @param str
*/
protected void setTitle(String str){
if (str != null || !TextUtils.isEmpty(str)){
TextView title_view = findViewById(R.id.title);
title_view.setText(str);
}
}
/**
* 显示返回按钮
* @param show
*/
protected void setBack(boolean show){
TextView back_view = findViewById(R.id.back);
if (show){
back_view.setVisibility(View.VISIBLE);
back_view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
finish();
}
});
}else{
back_view.setVisibility(View.INVISIBLE);
}
}
/**
* 普通页面跳转
*/
protected void openActivity(Class> Action){
startActivity(new Intent(this,Action));
}
}
LoginActivity.class
/**
* Created by aiyang on 2018/7/3.
* 登陆页面
*/
public class LoginActivity extends BaseActivity implements LoginView,View.OnClickListener{
EditText name;
EditText pwd;
Button submit;
ILoginPresenter presenter;
@Override
protected int setContentView() {
return R.layout.activity_login;
}
@Override
protected void init(Bundle savedInstanceState) {
setTitle("登录");
setBack(false);
initView();
presenter = new LoginPresentImpl(this,new UserInfo());
}
private void initView() {
name = findViewById(R.id.name);
pwd = findViewById(R.id.pwd);
submit =findViewById(R.id.submit);
submit.setOnClickListener(this);
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.submit){
String account = name.getText().toString().trim();
String password = pwd.getText().toString().trim();
if (!TextUtils.isEmpty(account) && !TextUtils.isEmpty(password)){
presenter.loginSubmit(account, password);
}else {
DialogUtil.showSimpleDialog(this,"错误提示","账户密码不能为空",null);
}
}
}
@Override
public void showProgress() {
DialogUtil.showProgress(this,"登陆中");
}
@Override
public void hideProgress() {
DialogUtil.dismissProgress();
}
@Override
public void loginSuccess() {
DialogUtil.showSimpleDialog(this, "登陆成功", "验证通过,是否进入到首页?", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
openActivity(MainActivity.class);
}
});
}
@Override
public void loginFail() {
DialogUtil.showSimpleDialog(this,"错误提示","账户密码不正确",null);
}
}
MainActivity.class
public class MainActivity extends BaseActivity{
@Override
protected int setContentView() {
return R.layout.activity_main;
}
@Override
protected void init(Bundle savedInstanceState) {
setTitle("首页");
setBack(true);
}
}
MVP高级使用。结合RXJava\Retrofit\okHttp等框架使用。