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 ...
随机推荐
- Ofbiz项目学习——阶段性小结——更新数据
一.根据一个字段进行修改 /** * 根据一个字段进行修改(这个条件字段可以是主键, 也可以不是主键) * @param dctx * @param context * @return */ publ ...
- SpringBoot整合Spring Data Elasticsearch
Spring Data Elasticsearch提供了ElasticsearchTemplate工具类,实现了POJO与elasticsearch文档之间的映射 elasticsearch本质也是存 ...
- Linux安装pycharm并添加图标到桌面
安装: 1.到pycharm官网下载Linux版本的pycharm包. 2.打开中端 cd到下载的文件夹,默认为 ~/Downloads/ 文件夹下 3.执行命令 tar -xvzf pycharm- ...
- Ansible自动部署tomcat
1.首先准备3台机器 ansible机器:192.168.52.34 目标主机:192.168.52.35 目标主机:192.168.52.36 2.关闭防火墙 [root@localhost ~]# ...
- Numpy | 12 数组操作
Numpy 中包含了一些函数用于处理数组,大概可分为以下几类: 修改数组形状 翻转数组 修改数组维度 连接数组 分割数组 数组元素的添加与删除 一.修改数组形状 函数 描述 reshape 不改变数据 ...
- 10 Unit Testing and Automation Tools and Libraries Java Programmers Should Learn
转自:https://javarevisited.blogspot.com/2018/01/10-unit-testing-and-integration-tools-for-java-program ...
- Singer 修改tap-s3-csv 支持minio 连接
singer 团队官方处了一个tap-s3-csv 的tap,对于没有使用aws 的人来说并不是很方便了,所以简单修改了 下源码,可以支持通用的s3 csv 文件的处理,同时发布到了官方pip 仓库中 ...
- 配送城市地址联动选择JQuery
记录一次使用jq实现3层地址联动选择流程!效果如图. 需要引入 jq.js.layer.js.layui.js.layui.css (icon图标) 二.选中后页面展示效果 三.页面展示HTML &l ...
- 使用mapreduce清洗简单日志文件并导入hive数据库
Result文件数据说明: Ip:106.39.41.166,(城市) Date:10/Nov/2016:00:01:02 +0800,(日期) Day:10,(天数) Traffic: 54 ,(流 ...
- 分析WordPress数据表之评论表(功能篇)
数据表分析 wp_comments(评论表) 该表字段,如下:comment_ID(评论ID)comment_post_ID(评论文章ID)comment_author(评论者用户名)comment_ ...