Android MVP模式简单介绍:以一个登陆流程为例
老的项目用的MVC的模式,最近完成了全部重构成MVP模式的工作,虽然比较麻烦,好处是代码逻辑更加清楚、简洁,流程更加清晰,对于后续版本迭代维护都挺方便。
对于一些想要学习MVP模式的同学来讲,百度搜出来的好多都没法直接转化为项目里可以直接用的东西,所以这里正好拿出自己项目里已经用了的,你们可以直接用到自己的项目里。当然,不可能把所有项目代码在这里放出来,所以就拿登陆的流程出来,这个比较合适也比较常用。
1、先看下包结构:
model:放一些bean类,以及网络处理类RetrofitManager,ServiceHelper(封装的网络请求类)等
view:放UI层需要实现的逻辑
presenter:放一些业务逻辑相关的接口及实现类

2、进入正题
首先,以登陆流程为例,简单画下流程图:

然后开始划分对应三个层的逻辑:
presenter:作为登录页面,涉及的业务逻辑有:记住密码,登录,保存登录之后获取的Token
public interface ILoginPresenter {
void rememberPassword(String account,String pwd);
void login(String phoneNum,String pwd);
void saveToken(String token);
}
LoginPresenterImpl:负责具体登陆逻辑及view层业务的调用,持有view层对象引用:iLoginView
public class LoginPresenterImpl implements ILoginPresenter {
private static final String TAG = "LoginPresenterImpl";
private String mMd5Pwd;
ILoginView mILoginView;
private Context mContext;
public LoginPresenterImpl(ILoginView iLoginView, Context context) {
this.mILoginView = iLoginView;
this.mContext = context;
}
@Override
public void rememberPassword(String account, String pwd) {
SPUtils.put(mContext, "remember_password", true);
SPUtils.put(mContext, "phoneNum", account);
SPUtils.put(mContext, "password", pwd);
}
@Override
public void login(String phoneNum, String pwd) {
if (TextUtils.isEmpty(phoneNum)) {
mILoginView.loginResult(false, Constant.PHONENUM_NULL);return;
}
if (!Utils.isMobileNO(phoneNum)) {
mILoginView.loginResult(false, Constant.PHONENUM_FALSE);return;
}
if (TextUtils.isEmpty(pwd)) {
mILoginView.loginResult(false, Constant.PWD_NULL);return;
}
mMd5Pwd = Utils.encrypt(pwd);
LogUtils.d(TAG, "pwd:" + pwd + "------------ mMd5Pwd:" + mMd5Pwd);
//判断网络是否可用
if (!Utils.isNetAvail()) {
mILoginView.loginResult(false, Constant.INTERNET_FAILED);
LogUtils.d(TAG, "网络不可用");
return;
}
//发起网络请求,查看手机号和密码是否正确
ServiceHelper.callEntity(RetrofitManager.getInstance().createReq(Login.class).getLoginData(phoneNum, mMd5Pwd), LoginBean.class, new OnResponseLisner<LoginBean>() {
@Override
public void onSuccess(LoginBean info) {
int mUid = info.getData().getUID();
String token = info.getData().getToken();
saveToken(token);
mILoginView.loginResult(true, String.valueOf(mUid));
}
@Override
public void onError(String errorMsg) {
mILoginView.loginResult(false, errorMsg);
}
});
}
@Override
public void saveToken(String token) {
if (!TextUtils.isEmpty(token)) {
//存储String值
SPUtils.put(mContext, "Token", token);
}
}
view:登陆结果的处理展示(由具体实现类MainActivity实现对应的方法)
public interface ILoginView {
void loginResult(Boolean result, String msg);
}
model:服务器返回的数据bean类
public class LoginBean {
public boolean Success;
public int Code;
public String ErrorMsg_zh;
public String ErrorMsg_en;
public DataBean Data;
public int ServerTime;
public String LogId;
public static class DataBean {
public int UID;
public String Name;
public String Phone;
public String Email;
public String FacePic;
public String Token;
}
最后,看下完整的登陆页面MainActivity(ILoginView实现类)的代码:
public class LoginActivity extends BaseActivity implements ILoginView {
@BindView(R.id.et_phoneNum)
EditText mEtPhoneNum;
@BindView(R.id.et_pwd)
EditText mEtPwd;
@BindView(R.id.iv_phoneNumClear)
ImageView mPhoneNumClear;
@BindView(R.id.iv_pwdClear)
ImageView mPwdClear;
@BindView(R.id.cb_checkbox)
CheckBox mCheckBox;
@BindView(R.id.btn_login)
Button mBtnLogin;
@BindView(R.id.avi_loading)
AVLoadingIndicatorView mAviLoading;
private String TAG = "LoginActivity";
private String mPhoneNum;
private String mPwd;
private ILoginPresenter mILoginPresenter;
@Override
public int getLayoutResId() {
return R.layout.activity_login;
}
@Override
protected void init() {
super.init();
mILoginPresenter = new LoginPresenterImpl(this, LoginActivity.this);
boolean isRemenber = (boolean) SPUtils.get(this, "remember_password", false);
LogUtils.d(TAG, "isRemenber:" + isRemenber);
if (isRemenber) {
//将账号和密码都设置到文本中
String account = (String) SPUtils.get(this, "phoneNum", "");
String password = (String) SPUtils.get(this, "password", "");
mEtPhoneNum.setText(account);
mEtPwd.setText(password);
mCheckBox.setChecked(true);
}
mBtnLogin.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
mAviLoading.setVisibility(View.VISIBLE);
mPhoneNum = mEtPhoneNum.getText().toString().trim();
mPwd = mEtPwd.getText().toString().trim();
mILoginPresenter.login(mPhoneNum, mPwd);
if (mCheckBox.isChecked()) {
mILoginPresenter.rememberPassword(mPhoneNum, mPwd);
} else {
SPUtils.remove(LoginActivity.this, "remember_password");
SPUtils.remove(LoginActivity.this, "phoneNum");
SPUtils.remove(LoginActivity.this, "password");
}
}
});
}
@Override
public void loginResult(Boolean result, String msg) {
if (result) {
LogUtils.d(TAG, "uid:" + msg);
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("uid", msg);
startActivity(intent);
} else {
CustomToast.show(this, msg + " 请稍后再试!");
}
mAviLoading.setVisibility(View.INVISIBLE);
}
3、总结,MVP结构图:
view层和Presenter层互相持有对方的引用,model只会被presenter层使用。

PS:觉得看了还是不太明白或是好像明白的同学可以自己亲自动手写一写,应该写完就完全可以明白了。
Android MVP模式简单介绍:以一个登陆流程为例的更多相关文章
- android MVP模式简单介绍
原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/ 前言 MVP作为一种MVC的演化版本在Android开发中受到 ...
- Android MVP模式简单易懂的介绍方式 (一)
Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...
- Android MVP模式简单易懂的介绍方式 (三)
Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 讲完M和P,接下来就要讲V了.View ...
- Android MVP模式简单易懂的介绍方式 (二)
Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 上一篇文章我们介绍完了Model的创建 ...
- Android MVP模式 简单易懂的介绍方式
主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200
- Android MVP模式
转自http://segmentfault.com/blogs,转载请注明出处Android MVP Pattern Android MVP模式\[1\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...
- android MVP模式介绍与实战
android MVP模式介绍与实战 描述 MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数 ...
- MVP 模式简单易懂的介绍方式
为什么用Android MVP 设计模式? 当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP 模式 的优势就充分显示出来了. MVP 模式是 MVC 模式在 Android 上的一种变体, ...
- Android MVP模式 谷歌官方代码解读
Google官方MVP Sample代码解读 关于Android程序的构架, 当前(2016.10)最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法. Repo ...
随机推荐
- Nginx是什么及作用?
一:介绍 nginx是一个高性能的HTTP和反向代理服务器,其特点是占用内存少,并发能力强. 二:名词介绍 代理服务器: 代理服务器英文全称是Proxy Server,其功能就是代理网络用户去取得网络 ...
- Eclipse中将java类打成jar包形式运行
记录一次帮助小伙伴将java类打成jar包运行 1.创建java project项目 file > new > project > java project 随便起一个项目名称,fi ...
- PostgreSQL Autovacuum和vacuum
1 基础知识 重点: 如果您的数据库运行了很久,并且从来没有打开过autovacuum,那么请在打开autovacuum之前全库手动运行vacuum analyze(可能要非常久的时间)完全禁用aut ...
- 用OKR让你的员工嗨起来
在<OKR工作法>这本书中,作者主要用了叙述故事的方式来讲解了在OKR实践的整个过程,这样的讲解方式让整本书显得生动有趣,却又处处是引人深思的道理.比如说TeaBee在第一次OKR实践失败 ...
- ABP 02 解决 界面为英文
原文:https://www.cnblogs.com/wswind/p/10313968.html 1.直接改数据库 2.在数据迁移前,更改默认值 注意: 我的项目已经初始化了,数据库已经都生成好了, ...
- npm link 的用法
npm link 的用法 先到对应的自定义包下执行 npm link 会读取对应的 packagejson 中的名称 然后到对应的目录下执行 npm link your/own/npm/name 就会 ...
- 云服务器搭建JDK+Tomcat+MySQL环境
一.首先租赁一台云服务器(阿里云服务器或者腾讯云服务器) 其实可以在windows电脑上使用VMware workstation来安装虚拟机进行操作,毕竟云服务器低配也是很贵的.不过可以使用学生价去租 ...
- Python 元编程
1.为函数添加包装器 总是存在这样的场景,在一个函数执行前后需要做一些操作处理,常见于日志创建.权限认证或者性能分析等.但有一个问题存在,那就是被装饰的函数,其元信息会丢失,函数引用会指向装饰器的返回 ...
- webpack vue-cli2 配置打包测试环境
目前vue-cli2上原配置是只有开发环境dev和线上环境prod的配置,但是我们实际场景上还有很多需要一个测试环境test,下面就是对测试环境的配置,将测试环境和线上环境的打包代码分开就不需要切来切 ...
- ansible-playbook--jia使用
#cat jia.yml - hosts: test-gfs user: dev gather_facts: true vars: PORT: "3306" MESAGE: &qu ...