Android MVP架构实现
最近在学习Android的MVP架构,在网上找了许多资料都没有一个清晰的认识,偶然看到简书上骆驼骑士前辈的文章,对MVP的实现过程有了一个较为清晰的认识。后又研究了一下Google官方Demo,分别对两种实现方式做了一个Demo进行对比。
对于Android MVP实现方式,借用一下骆驼骑士前辈的分析
目前常见的MVP在Android里的实践有两种解决方案:
1.直接将Activity看作View,让它只承担View的责任。
2.将Activity看作一个MVP三者以外的一个Controller,只控制生命周期。
下面我们来讲述一下这两种方式的实现过程。
第一种:Activity承担MVP中V的角色
我们以一个不需要网络请求的登录作为示例进行实现。
在这个MVP架构中,我们需要以下几个文件:
类型 | 文件名 |
---|---|
Model 接口 |
ILoginModel
|
View 接口 |
ILoginView
|
Presenter 接口 |
ILoginPresenter
|
Model 接口实现 |
ILoginModelImpl
|
View 接口实现 |
LoginActivity
|
Presenter 接口实现 |
ILoginPresenterImpl
|
首先,我们先定义一个实体类UserEntity,模拟服务器返回的数据。
UserEntity.java
public class UserEntity {/*** 响应码*/private int code;/*** 提示信息*/private String msg;/*** 用户名*/private String user_name;public int getCode() {return code;}public String getMsg() {return msg;}public String getUser_name() {return user_name;}public void setCode(int code) {this.code = code;}public void setMsg(String msg) {this.msg = msg;}public void setUser_name(String user_name) {this.user_name = user_name;}
}
接下来,我们需要编写ILoginModel
、ILoginView
、ILoginPresenter
三个接口
ILoginModel.java
import com.example.mvp.login.CallBack;public interface ILoginModel {/*** 登录相关的业务逻辑在此处理** @param username 账号* @param password 密码* @param callBack 回调接口*/void login(String username, String password, CallBack callBack);
}
ILoginView.java
import com.example.mvp.login.entity.UserEntity;public interface ILoginView {/*** 登录成功的回调显示** @param userEntity 实体类*/void showLoginSuccessMsg(UserEntity userEntity);/*** 登录失败的回调显示** @param errorMsg 失败信息*/void showLoginFailMsg(String errorMsg);
}
ILoginPresenter.java
public interface ILoginPresenter {/*** 连接 Model 和 View 的登录方法** @param username 账号* @param password 密码*/void login(String username, String password);
}
因为在Model中用到了一个回调接口CallBack,所以我们接下来定义一下这个接口:
CallBack.java
import com.example.mvp.login.entity.UserEntity;public interface CallBack {/*** 登录成功的回调** @param userEntity 实体类*/void onSuccess(UserEntity userEntity);/*** 登录失败的回调** @param errorMsg 错误信息*/void onFail(String errorMsg);
}
至此,MVP架构的准备工作都做好了,接下来我们开始实现这些接口,将各个接口连接起来,实现一个登录功能。
大家知道,Model是承担了数据处理和业务逻辑的功能,所以我们来实现一下ILoginModel
这个接口。在这个类中,我们假设当账号为 user,密码为 123456 时即登录成功。
LoginModelImpl.java
import com.example.mvp.login.CallBack;
import com.example.mvp.login.entity.UserEntity;public class LoginModelImpl implements ILoginModel {@Overridepublic void login(String username, String password, CallBack callBack) {if (username.equals("user") && password.equals("123456")) {// 模拟服务器返回的数据UserEntity userEntity = new UserEntity();userEntity.setCode(1);userEntity.setMsg("登录成功");userEntity.setUser_name("Vip User");callBack.onSuccess(userEntity);} else {callBack.onFail("用户名或密码错误");}}
}
接下来我们实现一下作为中间联系人的ILoginPresenter
接口:
LoginPresenterImpl.java
import com.example.mvp.login.CallBack;
import com.example.mvp.login.entity.UserEntity;
import com.example.mvp.login.model.ILoginModel;
import com.example.mvp.login.view.ILoginView;public class LoginPresenterImpl implements ILoginPresenter {/*** View*/private ILoginView view;/*** Model*/private ILoginModel model;/*** 构造方法** @param view 实现接口的类* @param model 实现接口的类*/public LoginPresenterImpl(ILoginView view, ILoginModel model) {this.view = view;this.model = model;}@Overridepublic void login(String username, String password) {//主动调用model中的login方法实现登录model.login(username, password, new CallBack() {@Overridepublic void onSuccess(UserEntity userEntity) {//如果登录成功,将登录成功的数据传递给View进行显示view.showLoginSuccessMsg(userEntity);}@Overridepublic void onFail(String errorMsg) {//如果登录失败,将登陆失败的数据传递给View显示view.showLoginFailMsg(errorMsg);}});}
}
最后一步,新建一个LoginActivity,实现ILoginView
,该activity的内容非常简单,只有两个EditText用于输入账号和密码,一个Button用于点击登录,在这里,只贴出Activity的代码:
LoginActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;import com.example.mvp.R;
import com.example.mvp.login.Presenter.ILoginPresenter;
import com.example.mvp.login.Presenter.LoginPresenterImpl;
import com.example.mvp.login.entity.UserEntity;
import com.example.mvp.login.model.LoginModelImpl;public class LoginActivity extends AppCompatActivity implements ILoginView {/*** Presenter*/private ILoginPresenter presenter;/*** 登录按钮*/private Button btn;/*** 用户名输入框*/private EditText etName;/*** 密码输入框*/private EditText etPwd;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);//实例化Presenterpresenter = new LoginPresenterImpl(this, new LoginModelImpl());//绑定控件btn = findViewById(R.id.btn);etName = findViewById(R.id.et_name);etPwd = findViewById(R.id.et_pwd);//实现登录的点击事件btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String username = etName.getText().toString();String password = etPwd.getText().toString();//检测账号密码均不为空时调用presenter的登录方法if ("".equals(username) || "".equals(password)) {Toast.makeText(LoginActivity.this, "用户名或密码不能为空", Toast.LENGTH_SHORT).show();} else {presenter.login(username, password);}}});}@Overridepublic void showLoginSuccessMsg(UserEntity userEntity) {Toast.makeText(this, userEntity.getUser_name() + "登录成功", Toast.LENGTH_SHORT).show();}@Overridepublic void showLoginFailMsg(String errorMsg) {Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();}
}
以上就是本例的全部代码,现在我们来整理一下整个创建流程:
- 创建一个实体类UserEntity,用于模拟服务器返回的数据;
- 创建
ILoginModel
、ILoginView
、ILoginPresenter
接口; - 创建一个
CallBack
接口,用于登录回调; - 实现M、P、V接口,创建
LoginModelImpl
、LoginPresenterImpl
、LoginActivity
,实现登录功能。
实现的效果如下:
我们再来整理一下整个登录过程是如何实现的:
- 在 LoginActivity 中声明一个 ILoginPresenter,初始化为 LoginPresenterImpl,向构造函数中传入两个参数—— LoginActivity、LoginModelImpl。
presenter = new LoginPresenterImpl(this, new LoginModelImpl());
- 点击 button,调用 presenter.login() ——
实际上调用的是 LoginPresenterImpl.login()
;
presenter.login(username, password);
- 在 LoginPresenterImpl.login() 中调用 model.login(),实现 CallBack 接口,将 CallBack 回调的数据推送给 View 进行显示 ——
实际上调用的是 LoginModelImpl.login()
;
model.login(username, password, new CallBack() {@Overridepublic void onSuccess(UserEntity userEntity) {//如果登录成功,将登录成功的数据传递给View进行显示view.showLoginSuccessMsg(userEntity);}@Overridepublic void onFail(String errorMsg) {//如果登录失败,将登陆失败的数据传递给View显示view.showLoginFailMsg(errorMsg);}});
- 在 model.login() 中实现登录判断,将登录结果通过 CallBack 接口提交给 Presenter;
if (username.equals("user") && password.equals("123456")) {// 模拟服务器返回的数据UserEntity userEntity = new UserEntity();userEntity.setCode(1);userEntity.setMsg("登录成功");userEntity.setUser_name("Vip User");callBack.onSuccess(userEntity);
} else {callBack.onFail("用户名或密码错误");
}
- 在 LoginActivity 实现的 onLoginSuccessMsg() 、onLoginFailMsg() 中处理登陆成功和失败的提示。
@Override
public void showLoginSuccessMsg(UserEntity userEntity) {Toast.makeText(this, userEntity.getUser_name() + "登录成功", Toast.LENGTH_SHORT).show();
}@Override
public void showLoginFailMsg(String errorMsg) {Toast.makeText(this, errorMsg, Toast.LENGTH_SHORT).show();
}
第二种:将Activity看作一个MVP三者以外的一个Controller,只控制生命周期
我们仍旧以一个不需要网络请求的登录作为示例进行实现。
在这个个MVP架构中,我们需要以下几个文件:
类型 | 文件名 |
---|---|
Model 接口 |
ILoginModel
|
View 接口 |
ILoginView
|
Presenter 接口 |
ILoginPresenter
|
Model 接口实现 |
ILoginModelImpl
|
View 接口实现 |
LoginFragment
|
Presenter 接口实现 |
ILoginPresenterImpl
|
Controller |
LoginActivity
|
大家可以看到,和上一个例子相比,我们多了一个 LoginFragment
,并且对 View 接口的实现并不是 LoginActivity
来实现了,而是改为LoginFragment
。( 其实在Google官方Demo里,View 和 Presenter 的接口是放在一个名为 Contract 的接口文件里的,此处为了更好的理解,将 View 和 Presenter 分别放置在一个文件里。)
因为这个Demo和上一个Demo并没有太大的区别,所以此处只贴出不同部分的代码片段。
LoginModelImpl.java (增加如下代码)
/*** 生成实例*/
private static LoginModelImpl instance = null;public static LoginModelImpl getInstance() {if (instance == null) {instance = new LoginModelImpl();}return instance;
}private LoginModelImpl() { }
LoginPresenterImpl.java(修改变量和构造方法)
/*** View*/
private ILoginView view;
/*** Model*/
private LoginModelImpl model;
/*** 构造方法** @param view 实现接口的类* @param model 实现接口的类*/
public LoginPresenterImpl(ILoginView view, LoginModelImpl model) {this.view = view;view.setPresenter(this);this.model = model;
}
ILoginView.java(增加如下方法)
/*** 设置Presenter** @param presenter*/
void setPresenter(ILoginPresenter presenter);
下面贴出 LoginActivity
和 LoginFragment
的代码供大家进行比较:
LoginActivity.java
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;import com.example.mvp.R;
import com.example.mvp.login.Presenter.LoginPresenterImpl;
import com.example.mvp.login.model.LoginModelImpl;public class LoginActivity extends AppCompatActivity {/*** Presenter*/LoginPresenterImpl presenter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_login);// 绑定FragmentFragmentManager fragmentManager = getSupportFragmentManager();LoginFragment loginFragment = (LoginFragment) fragmentManager.findFragmentById(R.id.frame_layout);if (loginFragment == null) {loginFragment = LoginFragment.newInstance();if (fragmentManager != null && loginFragment != null) {FragmentTransaction transaction = fragmentManager.beginTransaction();transaction.add(R.id.frame_layout, loginFragment);transaction.commit();}}//实例化Presenterpresenter = new LoginPresenterImpl(loginFragment, LoginModelImpl.getInstance());}
}
LoginFragment.java
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;import com.example.mvp.R;
import com.example.mvp.login.Presenter.ILoginPresenter;
import com.example.mvp.login.entity.UserEntity;public class LoginFragment extends Fragment implements ILoginView {/*** presenter*/private ILoginPresenter presenter;/*** 登录按钮*/private Button btn;/*** 用户名输入框*/private EditText etName;/*** 密码输入框*/private EditText etPwd;/*** 生成实例** @return loginFragment*/public static LoginFragment newInstance() {return new LoginFragment();}public LoginFragment() {}@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {View view = inflater.inflate(R.layout.fragment_login, container, false);//绑定控件btn = view.findViewById(R.id.btn);etName = view.findViewById(R.id.et_name);etPwd = view.findViewById(R.id.et_pwd);//实现登录的点击事件btn.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {String username = etName.getText().toString();String password = etPwd.getText().toString();//检测账号密码均不为空时调用presenter的登录方法if ("".equals(username) || "".equals(password)) {Toast.makeText(getContext(), "用户名或密码不能为空", Toast.LENGTH_SHORT).show();} else {presenter.login(username, password);}}});return view;}@Overridepublic void setPresenter(ILoginPresenter presenter) {this.presenter = presenter;}@Overridepublic void showLoginSuccessMsg(UserEntity userEntity) {Toast.makeText(getContext(), userEntity.getUser_name() + "登录成功", Toast.LENGTH_SHORT).show();}@Overridepublic void showLoginFailMsg(String errorMsg) {Toast.makeText(getContext(), errorMsg, Toast.LENGTH_SHORT).show();}
}
在本例中,大家可以看到,真正的 View 角色是由 Fragment 承担的,View 相关的操作都在 Fragment 中进行,Activity 不再承担View的角色,而是独立于MVP之外,成为一个单独的个体:
每一个Activity都拥有一个Fragment来作为View,然后每个Activity也对应一个Presenter,在Activity里只处理与生命周期有关的内容,并跳出MVP之外,负责实例化Model,View,Presenter,并负责将三者合理的建立联系,承担的就是一个上帝视角
上述两种模式,一种是实际操作上的简便,将Activity看做View,直接在Activity中实例化Presenter和Model;另一种是建立一个规范且正确的依赖关系,让Activity跳出MVP,负责建立M、V、P 三者的联系,相应的,操作上也会相对复杂,每个Activity都必须有一个独立的Fragment。两种模式,大家根据自己的需要进行取舍即可。
以上呢,即是本人的一些浅薄的见解,如有不全之处,欢迎大家指正。
Android MVP架构实现相关推荐
- [Android] Android MVP 架构下 最简单的 代码实现
Android MVP 架构下 最简单的 代码实现 首先看图: 上图是MVP,下图是MVC MVP和MVC的区别,在于以前的View层不仅要和model层交互,还要和controller层交互.而 ...
- Android MVP架构从入门到精通-真枪实弹
Android MVP架构从入门到精通-真枪实弹 一. 前言 二. MVC架构 1. MVC架构优缺点 A. 缺点 B. 优点 三. MVP架构 1. MVP架构优缺点 A. 缺点 B. 优点 四. ...
- 谈谈 Android MVP 架构 | 掘金技术征文
前言:本文所写的是博主的个人见解,如有错误或者不恰当之处,欢迎私信博主,加以改正!原文链接,demo链接 MVP 架构简介 说起 MVP 架构,相信很多朋友都看过,网上也有很多这方面的资料.博主使用 ...
- android mvp框架基类,Android MVP架构项目搭建封装,基类封装
综述 对于MVP (Model View Presenter)架构是从著名的MVC(Model View Controller)架构演变而来的.而对于Android应用的开发中本身可视为一种MVC架构 ...
- Android MVP架构模式
目录 概述 实例 Model View Presenter 后记 全部代码 Model View Presenter 概述 MVP模式是Android常见的的一种架构模式,全称是Model.View. ...
- Android MVP架构
Android 架构的理解昨天看了Android框架模式(1)-MVP入门,感觉理解起来有点困难,我就重新把java回调重新理解了一遍,并写了一篇博客,有需要的朋友可以看一看,java回调机制,下面我 ...
- 适用于小型项目的 Android MVP 架构
MVP 架构介绍 其实没什么好介绍的了,网上有很多相关的文章,我就不去 copy 了,反正就是 Google 公司推出的一个适合中大型 Android 项目开发的架构. 之前做了一个项目使用的就是 M ...
- android 服务架构,Android MVP架构搭建
目录 引言 为什么用MVP架构 MVP理论知识 乞丐版MVP架构模式的代码实现 MVP中的代码复用场景 平民版MVP架构 - base层顶级父类 Fragment怎么办 时尚版MVP架构 - Mode ...
- android MVP架构分享
闲来无事,写了一套MVP代码架构,希望能给各位分享一些程序逻辑: 一.java版架构 https://github.com/VcStrong/RxRetrofitMVPDemo.git mvp-v1和 ...
- Android —MVP架构—登录页面示例
1.MVP的诞生 以下内容都是从安卓的角度分析: 首先要了解什么是MVC架构: 图片来源网络 View:对应XML文件及Activity或fragment,因为许多修改视图的操作在Activity中实 ...
最新文章
- 卸载破解的Navicat!操作所有的数据库靠它就够了!
- 科学家发现跨越生命的重要门槛或许没那么难
- Oracle 11g Data Guard 使用duplicate from active database 创建 standby database
- APP时代,市场选择是个技术活
- Asp.net 后台添加CSS、JS、Meta标签
- mysql表内增加一个字段并赋值
- 南核目录2020pdf_北核+南核|《消费经济》2020年重点选题
- [Jarvis OJ - PWN]——[XMAN]level3
- 使用POI导入和导出 Excel文件
- MyBatis框架 注解
- c++ 字符串拼接_python字符串零碎总结
- 企业全面运营管理沙盘模拟心得_企业经营沙盘模拟心得体会
- 模拟CMOS集成电路设计基础 第一章 第二章开头
- 教你六步拆解 DDD领域驱动设计落地实践
- ERC20接口下USDT代币的深入解析
- 关于程序集成线上支付模块
- 人民日报申论万能结构
- 微信开发-NATAPP的使用
- docker-compose 部署 php + nginx + mysql + redis
- 计算机怎么不休眠,怎么设置电脑不休眠?