ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Android MVP模式深入实践探索(一),我浪费了自己职业生涯的黄金5年

2021-12-17 13:34:35  阅读:306  来源: 互联网

标签:MVP 职业生涯 void mLoginView Override Android View public android


说起MVP就不得不提起MVC, 因为MVP的是在MVC的基础上优化而来的:

MVC角色说明:

| 角色 | 职责 |

| :-- | :-- |

| View | 视图界面层,与用户发生交互,接收用户输入的请求转发给Controller处理 |

| Controller | 接收View的请求, 从视图层获取数据,执行业务逻辑,并调用Model层进行数据存取 |

| Model | 执行数据存取的业务逻辑,并根据业务模型通知视图层更新(一般是通过观察者模式) |

MVP角色说明:

| 角色 | 职责 |

| :-- | :-- |

| View | 视图界面层,与用户发生交互,接收用户输入的请求转发给Presenter处理 |

| Presenter | 接收View的请求, 从视图层获取数据,执行业务逻辑,并调用Model层进行数据存取,同时会调用View层的接口将数据更新到视图 |

| Model | 执行数据存取的业务逻辑,并将数据返回给Presenter层 |

可以看到MVP与MVC最大的区别就是MVP解耦了View层和Model层,两者不直接发生交互而是通过P层,而在MVC中Model还是会跟View层发生交互的。

传统的MVC模式更加适合于大型项目的开发,对于小型项目应用MVC反而显得臃肿繁琐,就像我们以前经常在Activity中最喜欢写的代码一样:UI处理、网络请求、数据存取等全部业务都放在Activity中来完成,这就像一个大杂烩,此时的Activity几乎兼顾了MVC中的所有角色,实际上在我看来它此时根本就不具备任何模式可言。而MVP模式的出现将臃肿的部分分解开来,恰好适合于小型的应用程序,比如移动端的应用,并且对单元测试也比较友好,所以大家都在提倡用这个模式进行开发。

按照惯例,还是从一个简单的登录页面来演示MVP的基本使用

《Android学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》

【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享

(几乎我看过的所有关于MVP的文章貌似都是拿登录页面来入门的。。)

布局页面:

在这里插入图片描述

布局activity_login.xml代码:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android=“http://schemas.android.com/apk/res/android”

android:layout_width=“match_parent”

android:layout_height=“match_parent”

android:orientation=“vertical”

android:gravity=“center”

<EditText

android:id="@+id/edit_user_name"

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:inputType=“text”

android:maxLines=“1”

android:hint=“请输入用户名”

android:textSize=“16sp”

android:textColor="@color/black" />

<EditText

android:id="@+id/edit_user_password"

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:inputType=“textPassword”

android:maxLines=“1”

android:hint=“请输入密码”

android:textSize=“16sp”

android:textColor="@color/black" />

<Button

android:id="@+id/btn_login"

android:layout_width=“match_parent”

android:layout_height=“wrap_content”

android:layout_marginTop=“20dp”

android:text=“登录”

android:textSize=“16sp”

android:textColor="@color/black"

/>

LoginActivity代码:

public class LoginActivity extends Activity implements View.OnClickListener {

private EditText mUserNameEdit;

private EditText mUserPasswordEdit;

private Button mLoginBtn;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_login);

initView();

}

private void initView() {

mUserNameEdit = (EditText) findViewById(R.id.edit_user_name);

mUserPasswordEdit = (EditText) findViewById(R.id.edit_user_password);

mLoginBtn = (Button) findViewById(R.id.btn_login);

mLoginBtn.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.btn_login:

//TODO

break;

default:

break;

}

}

}

如果是传统的MVC的话,到这一步基本就结束了,接下来就开始在LoginActivity中搞事情作死了。。

如果使用MVP的话,接下来我们需要建立几个package来存放对应的角色:

在这里插入图片描述

其中view包下存放activity、fragment等UI控件,iview包下存放presenter与view进行交互的接口类,我们把LoginActivity放入view/activity包中:

在这里插入图片描述

其他包下面的情况:

在这里插入图片描述

在MVP中为了解耦Presenter跟View和Model的交互都通过接口进行,所以新建一个跟LoginActivity交互的接口类ILoginView

public interface ILoginView {

/** 获取输入框的登录用户名 */

String getUserName();

/** 获取输入框的用户密码 */

String getUserPassword();

/** 显示Toast提醒 */

void showToast(String msg);

/** 登录成功的UI处理 */

void onLoginSuccess();

/** 登录失败的UI处理 */

void onLoginFail();

/** 显示加载中弹窗 */

void showProgressDialog();

/** 隐藏加载中弹窗 */

void hideProgressDialog();

/** 获取当前UI页面的上下文 */

Context getContext();

}

view接口类中定义的基本都是一些UI数据或者显示UI控件的方法,然让LoginActivity实现这个接口:

public class LoginActivity extends Activity implements ILoginView, View.OnClickListener {

private EditText mUserNameEdit;

private EditText mUserPasswordEdit;

private Button mLoginBtn;

public ProgressDialog mProgressDialog;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_login);

initView();

}

private void initView() {

mUserNameEdit = (EditText) findViewById(R.id.edit_user_name);

mUserPasswordEdit = (EditText) findViewById(R.id.edit_user_password);

mLoginBtn = (Button) findViewById(R.id.btn_login);

mLoginBtn.setOnClickListener(this);

}

@Override

public void onClick(View v) {

switch (v.getId()) {

case R.id.btn_login:

//TODO

break;

default:

break;

}

}

@Override

public String getUserName() {

return mUserNameEdit.getText().toString();

}

@Override

public String getUserPassword() {

return mUserPasswordEdit.getText().toString();

}

@Override

public void showToast(String msg) {

ToastUtils.showToast(this, msg);

}

@Override

public void onLoginSuccess() {

ToastUtils.showToast(this, “登录成功”);

//跳转首页

gotoHomeActivity();

finish();

}

@Override

public void onLoginFail() {

ToastUtils.showToast(this, “登录失败”);

}

@Override

public void showProgressDialog() {

if (mProgressDialog == null) {

mProgressDialog = DialogUtils.showSpinningProgressDialog(this, “正在登录中…”, false);

} else {

if (!mProgressDialog.isShowing()) {

mProgressDialog.show();

}

}

}

@Override

public void hideProgressDialog() {

if (mProgressDialog != null) {

mProgressDialog.dismiss();

}

}

@Override

public Context getContext() {

return this;

}

/** 跳转首页 */

private void gotoHomeActivity() {

Intent intent = new Intent(this, MainActivity.class);

startActivity(intent);

}

}

View层到此就完事了,接下来实现PresenterModel角色的接口和实现类

Presenter接口和实现类:

public interface ILoginPresenter {

/** 登录操作逻辑处理 */

void login();

/** 登录成功逻辑处理 */

void onLoginSuccess();

/** 登录失败逻辑处理 */

void onLoginFail(String errMsg);

}

public class LoginPresenter implements ILoginPresenter {

private ILoginView mLoginView;

private ILoginModel mLoginModel;

public LoginPresenter(ILoginView loginView) {

mLoginView = loginView;

mLoginModel = new LoginModelImpl(this);

}

@Override

public void login() {

// 对用户名和密码的校验逻辑,这里只简单判空,实际可以加更多校验

if (TextUtils.isEmpty(mLoginView.getUserName())) {

mLoginView.showToast(“请输入用户名”);

return;

}

if (TextUtils.isEmpty(mLoginView.getPassword())) {

mLoginView.showToast(“请输入密码”);

return;

}

//判断网络是否可用

if (!NetUtils.checkNetState(mLoginView.getContext())) {

mLoginView.showToast(“当前无网络连接,请检查网络”);

return;

}

//显示登录进度弹窗

mLoginView.showProgressDialog();

//调用model层发起登录请求

mLoginModel.sendLoginRequest(mLoginView.getUserName(), mLoginView.getPassword());

}

/** 登陆成功 */

@Override

public void onLoginSuccess() {

//隐藏登录进度弹窗

mLoginView.hideProgressDialog();

//回调View层接口

mLoginView.onLoginSuccess();

}

/** 登陆失败 */

@Override

public void onLoginFail(String errMsg) {

//隐藏登录进度弹窗

mLoginView.hideProgressDialog();

//回调View层接口

mLoginView.onLoginFail(errMsg);

}

}

可以看到在LoginPresenter的实现类当中分别持有了ILoginViewILoginModel两个接口,LoginPresenter通过这两个接口分别与LoginActivity和LoginModel进行交互。其中ILoginView变量是通过构造函数传递进来的,而ILoginModel则是在构造函数内部创建的。

Model接口和实现类:

public interface ILoginModel {

/** 发起登录请求 */

void sendLoginRequest(String userName, String password);

}

public class LoginModelImpl implements ILoginModel {

private static final String API_LOGIN = “/mobile/login”;

private ILoginPresenter mPresenter;

标签:MVP,职业生涯,void,mLoginView,Override,Android,View,public,android
来源: https://blog.csdn.net/m0_64382868/article/details/121994109

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有