老的项目用的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模式简单介绍:以一个登陆流程为例的更多相关文章

  1. android MVP模式简单介绍

    原文 http://zhengxiaopeng.com/2015/02/06/Android%E4%B8%AD%E7%9A%84MVP/ 前言 MVP作为一种MVC的演化版本在Android开发中受到 ...

  2. Android MVP模式简单易懂的介绍方式 (一)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...

  3. Android MVP模式简单易懂的介绍方式 (三)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 讲完M和P,接下来就要讲V了.View ...

  4. Android MVP模式简单易懂的介绍方式 (二)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 上一篇文章我们介绍完了Model的创建 ...

  5. Android MVP模式 简单易懂的介绍方式

    主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200

  6. Android MVP模式

    转自http://segmentfault.com/blogs,转载请注明出处Android MVP Pattern Android MVP模式\[1\]也不是什么新鲜的东西了,我在自己的项目里也普遍 ...

  7. android MVP模式介绍与实战

    android MVP模式介绍与实战 描述 MVP模式是什么?MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数 ...

  8. MVP 模式简单易懂的介绍方式

    为什么用Android MVP 设计模式? 当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP 模式 的优势就充分显示出来了. MVP 模式是 MVC 模式在 Android 上的一种变体, ...

  9. Android MVP模式 谷歌官方代码解读

    Google官方MVP Sample代码解读 关于Android程序的构架, 当前(2016.10)最流行的模式即为MVP模式, Google官方提供了Sample代码来展示这种模式的用法. Repo ...

随机推荐

  1. jquery-ui.min.js的draggable()拖拽功能

    <!doctype html> <html lang="en"> <head> <meta charset="utf-8&quo ...

  2. UI系统的三个主要关系

    1.UI的结构.组织和组件.布局.渲染效率:(系统内置的组件有哪些?) 2.UI与事件的关系: 3.UI与数据的关系:

  3. 伯克利套接字(BSD Socket)

    http://blog.csdn.net/blueman2012/article/details/6693605#socket.28.29 伯克利套接字(Berkeley sockets),也称为BS ...

  4. Windows10 Docker镜像加速

    https://dockerhub.azk8s.cn #Azure 中国镜像 https://reg-mirror.qiniu.com #七牛云加速器 https://registry.docker- ...

  5. 使用solr将CSV/XML/DB/JSON数据发布为Rest Service

    Download http://lucene.apache.org/solr/downloads.html Apache Solr入门基础——Windows下安装与配置 https://blog.cs ...

  6. systemd socket activation golang demo

    service define rongapp.service [Unit] Description=rong Hello World HTTP Requires=network.target rong ...

  7. 修改 oracle xe 默认中文字符集成为:SIMPLIFIED CHINESE_CHINA.ZHS16GBK

    修改 oracle xe 默认中文字符集成为:SIMPLIFIED CHINESE_CHINA.ZHS16GBK Oracle XE 执行安装程序后,很简单的默认为  SIMPLIFIED CHINE ...

  8. Spark 部署即提交模式意义解析

    Spark 的官方从 Cluster Mode Overview 中,官方向我们介绍了 cluster 模式的部署方式. Spark 作为独立进程在集群上运行,他们通过 SparkContext 进行 ...

  9. 一起学Makefile(一)

    make和makefile makefile文件帮助我们记录了整个项目工程的所有需要编译的文件列表,这样我们在编译时仅需要输入简单的make命令就能编译出我们期望的结果. makefile文件反映了整 ...

  10. nginx 反向代理之 proxy_redirect

    proxy_redirect 该指令用来修改被代理服务器返回的响应头中的Location头域和“refresh”头域. 语法结构为: proxy_redirect redirect replaceme ...