Android(安卓)MVP设计模式介绍(附简单Demo下载)
16lz
2021-12-04
推荐阅读:
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对比
(1)相通之处
因为MVP是由经典的设计模式MVC演变而来,它们的基本思想有相通之处:Controller/Presenter负责逻辑的处理,Model提供数据,View负责显示。
(2)MVC的缺陷
- 在MVC模型里,更关注模型层(Model)的不变。因为一个模型层(Model)可以被多个视图层(View)重用,Model不依赖于View,但是View是依赖于Model的。
- 在MVC模型里,视图层无法实现独立重用。视图层需要持有控制层Activity的引用才能进行UI引用。不仅如此,视图层(View)是可以直接访问模型层(Model)的数据,从而视图层不可避免会涉及一些业务逻辑。由于在View里实现的业务逻辑是无法被重用的,导致要更改和重用View变得比较困难。
- 由于模型操作接口的不同,视图可能需要多次调用模型才能获得足够的显示数据,不必要的频繁访问未变化数据的,也损害一定性能。
(3)两者区别
在MVP中视图层(View)不能直接访问模型层(Model),它们之间通过Presenter(Controller)来进行通信的。这一点很好的弥补了MVC的设计缺陷,使View与Model实现完全分离。View无法直接从Model中读取数据,所有的交互都发生在 Presenter层(Controller)。如下图所示:
MVP代码案例
CSDN下载本案例:http://download.csdn.net/download/csdn_aiyang/10194951
(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); }}
总结
(1)优点
- 项目结构清晰,解耦程度高,每个功能相互之间独立,可单独测试。
- 代码维护性高,代码出现Bug,能够快速定位。
- 功能扩展性强,增加业务功能时,并不需要去修改原始代码,只需增加相应的业务代码即可。
(2)缺点
- 出现大量的presenter,增加了项目类的数量,代码量增大,项目依然看起来臃肿,有时业务简单就直接一个Activity搞定了。
- 有时Activity和presenter有强引用关系,使用不当的话,容易出现内存泄漏的问题。
- presenter与 View 之间的联系过与紧密,一旦视图变更,presenter也随之变更。
CSDN下载:http://download.csdn.net/download/csdn_aiyang/10194951
MVP高级使用。结合RXJava\Retrofit\okHttp等框架使用。
Githup地址:https://github.com/aiyangtianci/MVPDemo
更多相关文章
- android实用代码片段
- Android(安卓)Handler 分析学习
- inflater在ListView中的使用
- Android(安卓)开机自动启动服务
- Android基于opencv进行图像识别并找出中心点和轮廓
- android Preference之android:dependency(列表依赖关系)
- Android全屏--两种activity的实现方式
- android背景选择器总结
- android下访问sd卡和网络的权限