老的项目用的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. iOS系统的两个循环

    1.事件循环: 2.显示循环:displaylink:系统定时从gpu缓存获取图片信息显示在屏幕.

  2. Arduino OV7670 live image over USB to PC

    https://www.youtube.com/watch?v=L9DTW1ulsT0 https://www.youtube.com/watch?v=Dp3RMb0e1eA

  3. 常用方法 DataTable转换为Entitys

    备注:摘自网上 有附地址 public static List<T> DataTableToEntities<T>(this DataTable dt) where T : c ...

  4. STL next_permutation 全排列

    调用方法: ]={,,,}; )){ ;i<;i++) printf("%d ",arr[i]); puts(""); } 测试效果: 注:可以看到1 2 ...

  5. 20181107 模拟赛T1:快乐传递政治正确版

    问题描述 David 有很多好朋友.有些期末季刚结束,有些人很快乐,但有些不太快乐,David 想把快乐传递给每个人,作为心理学大师,他准备了如下计划:David 的朋友中有 n 个男生和 m 个女生 ...

  6. NodeJS代码组织与部署

    使用NodeJS编写程序前,为了有个良好的开端,首先需要准备好代码的目录结构和部署方式,就如同修房子要先搭脚手架.本章将介绍与之相关的各种知识. 一.模块路径解析规则 我们已经知道,require函数 ...

  7. [西软xms]会员卡消费和余额情况表

    select * from vipcard; #过滤卡类型财富卡(CFK)权益卡(QYK)幸福卡(XFK) select id from vipcard where (card_class ='XFK ...

  8. nginx 日志之 access_log

    web服务器的访问日志是非常重要的,我们可以通过访问日志来分析用户的访问情况, 也可以通过访问日志发现一些异常访问,比如cc攻击. 格式: access_log /path/to/logfile fo ...

  9. Oracle 的查询组合语句

    select   a.core_txn_srl_no||a.c_dept||a.c_batch||lpad(a.c_opr_no,5,'0')||case a.txn_dr_cr_ind when ' ...

  10. OpenTK学习笔记:C#的中开发OpenGL程序的4种开源封包库SharpGL、CsGL、OpenTK、Tao框架的简单对比

    最近要在C#的语言环境下开发OpenGL程序,参考了网上的博客论坛http://www.cnblogs.com/hanyonglu/archive/2012/06/12/2546581.html,总结 ...