老的项目用的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 ...
随机推荐
-
读javascript高级程序设计10-DOM
一.节点关系 元素的childNodes属性来表示其所有子节点,它是一个NodeList对象,会随着DOM结构的变化动态变化. hasChildNodes():是否有子节点. var headline ...
-
MyBatis的一些基本操作
在学校里只学过一点点的hibernate基础,但是这几天被熊哥叫去写好几个类的接口,所以就去百度了一下mybatis的接口方式怎么使用.1定义接口,并且定义其中要使用到的方法,这里必须注意到的是方法名 ...
-
iOS UIApplicationDelegate
1.- (void)applicationWillResignActive:(UIApplication *)application说明:当应用程序将要入非活动状态执行,在此期间,应用程序不接收消息或 ...
-
了解Unix进程(1)
今天瞎看 看到一本了解Unix进程 -- 理解UNIX进程 的书 不错,可以看看,使用的ruby语言,第一章讲的是一些基础的知识 1.输出进程号和父进程号: puts Process.pid # 得到 ...
-
php simple_html_dom 一个iconv错误引起解析中断的问题,貌似内存溢出
环境: $pageNum = 8; for ($i = 1; $i < $pageNum; $i++) { $html = new simple_html_dom(); $host = 'htt ...
-
angular $modal模态框
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
-
【转载】 TensorflowOnSpark:1)Standalone集群初体验
原文地址: https://blog.csdn.net/jiangpeng59/article/details/72867368 作者:PJ-Javis 来源:CSDN --------------- ...
-
ABP框架学习
一.总体与公共结构 1,ABP配置 2,多租户 3,ABP Session 4,缓存 5,日志 6,设置管理 7,Timing 8,ABPMapper 9,发送电子邮件 二.领域层 10,实体 11, ...
-
python学习笔记第一周
目录: 一.基础概念 1.变量与常量介绍 2.引号的使用 3.条件判断 4.while与for循环 5.input输入 6.getpass模块 7.python编码 二.作业 1.个人登录系统 2.多 ...
-
Java String常见面试题汇总
String类型的面试题 1. String是最基本的数据类型吗? 基本数据类型包括byte,int,char,long,float,double,boolean,short一共八个. ...