Android学习探索之运用MVP设计模式实现项目解耦
前言:
一直致力于提高开发效率降低项目耦合,今天想抽空学习一下MVP架构设计模式,学习一下如何运用到项目中。
MVP架构设计模式
MVP模式是一种架构设计模式,也是一种经典的界面模式。MVP中的M代表Model, V是View, P是Presenter。
- Model 业务逻辑和实体模型
- View 代表对应布局文件以及一个将UI界面提炼而抽象出来的接口。
- Presenter Model和View之间的桥梁
为什么采用MVP
- 降低耦合度
- 模块职责划分明显
- 利于测试驱动开发
- 代码复用
- 隐藏数据
- 代码灵活性
举个栗子说明一下
先看下整个栗子的结构示意图

1)首先我们先看M层
Model代表业务逻辑和实体模型,栗子中的M层包含一个实体类UserEntity,具体代码如下:
public class UserEntity {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
一个获取user列表的契约接口类IUserModel
public interface IUserModel {
void loadUserEntities(IGetUserEntitiesListener listener);
}
一个实现IUserModel的实现类UserModelImpl
public class UserModelImpl implements IUserModel {
@Override
public void loadUserEntities(final IGetUserEntitiesListener listener) {
//模拟网络请求数据过程
new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
@Override
public void run() {
List<UserEntity> userModels = new ArrayList<>();
int testCount = 20;
for (int i = 0; i < testCount; i++) {
UserEntity userModel = new UserEntity();
userModel.setAge(i * 5);
userModel.setName(String.format("李%d", i));
userModels.add(userModel);
}
listener.onGetUserEntities(userModels);
}
}, 3000);
}
}
回调结果的IGetUserEntitiesListener 接口类
public interface IGetUserEntitiesListener {
void onGetUserEntities(List<UserEntity> userEntities);
}
2)V层就是页面的展示与加载
这里的V层为一个接口契约类和Activity,负责View的绘制以及与用户交互,首先看下契约接口类
public interface ILoadDataView<T> {
void startLoading();//开始加载
void loadFailed();//加载失败
void loadSuccess(List<T> list);//加载成功
void finishLoading();//结束加载
}
Activity代码如下
public class MainActivity extends AppCompatActivity implements ILoadDataView<UserEntity> {
private MyAdapter mMyAdapter;
private ProgressDialog mProgressDialog;
private LoadUserEntitiesPresenter mLoadListPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initViews();
}
private void initViews() {
ListView testListView = (ListView) findViewById(R.id.test_listView);
mMyAdapter = new MyAdapter(this);
testListView.setAdapter(mMyAdapter);
mLoadListPresenter = new LoadUserEntitiesPresenter(this);
findViewById(R.id.test_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mMyAdapter.removeDatas();
mMyAdapter.notifyDataSetChanged();
mLoadListPresenter.loadUserEntities();
}
});
}
@Override
public void startLoading() {
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setMessage("正在加载中");
mProgressDialog.show();
}
@Override
public void loadFailed() {
}
@Override
public void loadSuccess(List<UserEntity> list) {
mMyAdapter.addDatas(list);
mMyAdapter.notifyDataSetChanged();
}
@Override
public void finishLoading() {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
3)P层负责完成View于Model间的交互,由P分别操作M层和V层,是他们之间的桥梁
首先看下Presenter的实现,包括一个ILoadUserEntitiesPresenter契约接口类和LoadUserEntitiesPresenter实现类
ILoadUserEntitiesPresenter类代码
public interface ILoadUserEntitiesPresenter {
void loadUserEntities();
}
LoadUserEntitiesPresenter实现类
public class LoadUserEntitiesPresenter implements ILoadUserEntitiesPresenter {
private ILoadDataView<UserEntity> mILoadListView;
private IUserModel mUserModel;
public LoadUserEntitiesPresenter(ILoadDataView<UserEntity> mILoadListView) {
this.mILoadListView = mILoadListView;
this.mUserModel = new UserModelImpl();
}
@Override
public void loadUserEntities() {
mILoadListView.startLoading();
mUserModel.loadUserEntities(new IGetUserEntitiesListener() {
@Override
public void onGetUserEntities(List<UserEntity> userEntities) {
if (userEntities != null && !userEntities.isEmpty()) {
mILoadListView.loadSuccess(userEntities);
} else {
mILoadListView.loadFailed();
}
mILoadListView.finishLoading();
}
});
}
}
为了保证栗子能够正常运行,顺便贴出其他的代码
public class MyAdapter extends BaseAdapter {
private List<UserEntity> mUserModels;
private Context mContext;
public MyAdapter(Context mContext) {
this.mContext = mContext;
this.mUserModels = new ArrayList<>();
}
@Override
public int getCount() {
return mUserModels != null ? mUserModels.size() : 0;
}
@Override
public Object getItem(int position) {
return mUserModels.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;
if (convertView == null) {
viewHolder = new ViewHolder();
convertView = viewHolder.bindVIew();
convertView.setTag(viewHolder);
} else {
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.bindData(position);
return convertView;
}
public void addDatas(List<UserEntity> modelList) {
if (modelList == null || modelList.isEmpty()) {
return;
}
mUserModels.addAll(modelList);
}
public void removeDatas() {
mUserModels.clear();
}
public class ViewHolder {
private TextView mTextView;
public View bindVIew() {
View convertView = LayoutInflater.from(mContext).inflate(R.layout.item_listview, null);
mTextView = (TextView) convertView.findViewById(R.id.test_textview);
return convertView;
}
public void bindData(int position) {
UserEntity userModel = mUserModels.get(position);
mTextView.setText(String.format("name:%s \nage:%d", userModel.getName(), userModel.getAge()));
}
}
}
MyAdapter
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.whoislcj.testmvp.MainActivity"> <Button
android:id="@+id/test_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="20dp"
android:text="测试mvp"/> <ListView
android:id="@+id/test_listView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"/> </LinearLayout>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/test_textview"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="50dp"
android:layout_margin="10dp"
android:background="@android:color/white"
android:gravity="center"
android:orientation="vertical"
android:textColor="@android:color/black"
android:textSize="16sp"/>
item_listview.xml
总结:
这里仅仅就是MVP的简单实现,为了方便简单的认识MVP分层以及各层的职责与作用。
Android学习探索之运用MVP设计模式实现项目解耦的更多相关文章
- Android学习探索之Java 8 在Android 开发中的应用
前言: Java 8推出已经将近2年多了,引入很多革命性变化,加入了函数式编程的特征,使基于行为的编程成为可能,同时减化了各种设计模式的实现方式,是Java有史以来最重要的更新.但是Android上, ...
- 学习RxJava+Retrofit+OkHttp+MVP的网络请求使用
公司的大佬用的是这一套,那我这个菜鸟肯定要学习使用了. 我在网上找了很多文章,写的都很详细,比如 https://www.jianshu.com/u/5fd2523645da https://www. ...
- android学习日记28--Android中常用设计模式总结
一.综述 设计模式,根据前人经验总结出常见软件工程问题的解决思想套路.GoF一共归纳了23种设计模式,当然还有人扩充,不止这些.设计模式主要利用面向对象语言的特性,而android 的设计主要用JAV ...
- android学习日记27--Dialog使用及其设计模式
1.Dialog概述 对话框一般是一个出现在当前Activity之上的一个小窗口,处于下面的Activity失去焦点, 对话框接受所有的用户交互. 对话框一般用于提示信息和与当前应用程序直接相关的小功 ...
- Android学习探索之本地原生渲染 LaTeX数据公式
前言: 一直致力于为公司寻找更加高效的解决方案,作为一款K12在线教育App,功能中难免会有LaTeX数学公式的显示需求,这部分公司已经实现了此功能,只是个人觉得在体验和效率上还是不太好,今天来聊一下 ...
- Android学习探索之App多渠道打包及动态添加修改资源属性
前言: 关于Android渠道打包是一个比较老的话题,今天主要记录总结一下多渠道打包以及如果动态配置修改一些资源属性.今天以公司实际需求为例进行演示,由于项目复用很多公共的业务组件,而且业务组件之间的 ...
- Android为TV端助力 MVP设计模式!
实现原理: MainActivity 用来更新UI,和显示业务逻辑的结果! LoginPresenterCompl 用来处理 业务逻辑 ILoginPresenter 业务处理类抽象出来的接口 ILo ...
- Android学习笔记(一)——新建一个项目
//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 1.打开Android Studio时出现以下界面,点击”start a new Android Studio ...
- android学习日记03--常用控件Dialog
常用控件 9.Dialog 我们经常会需要在Android界面上弹出一些对话框,比如询问用户或者让用户选择.这些功能我们叫它Android Dialog对话框 对话框,要创建对话框之前首先要创建Bui ...
随机推荐
- 【2-26】string/math/datetime类的定义及其应用
一string类 (1)字符串.Length Length作用于求字符串的长度,返回一个int值 (2)字符串.TrimStart(); TrimStart():可删除前空格,返回一个stri ...
- Triangle Problems
Triangle Problem songxiuhuan 宋修寰 Import the Junit and eclemma Choose the project and right click, ch ...
- 用C++11实现C++17的apply(动态数组用作函数参数)
标题有点错误,apply是用tuple做参数,调用一个函数.这个标题是为了能更好的适配搜索关键字. 动态数组用作函数参数更适合嵌入了脚本环境的C++程序,比如lua或javascript(js). 若 ...
- layer弹出层框架alert与msg详解
ayer至今仍作为layui的代表作,她的受众广泛并非偶然,而是这五年多的坚持,不断完善和维护.不断建设和提升社区服务,使得猿们纷纷自发传播,乃至于成为今天的Layui最强劲的源动力.目前,layer ...
- 机器学习基石 2 Learning to Answer Yes/No
机器学习基石 2 Learning to Answer Yes/No Perceptron Hypothesis Set 对于一个线性可分的二分类问题,我们可以采用感知器 (Perceptron)这种 ...
- mybatis基础学习3---特殊sql语句(备忘)
1: 2: 3:resultMap的用法
- php学习测试题目
<?php header("content-type:text/html;charset=utf-8"); /* 1.银行给客户每天万分之四的利率,本金10 ...
- 实用 .htaccess 用法大全
这里收集的是各种实用的 .htaccess 代码片段,你能想到的用法几乎全在这里. 免责声明: 虽然将这些代码片段直接拷贝到你的 .htaccess 文件里,绝大多数情况下都是好用的,但也有极个别情况 ...
- jquery-scrollstop
$(window) .on("scrollstart", function() { // Paint the world yellow when scrolling starts. ...
- POST与GET
面试如果被问到这个问题,相信很多人都是会心一笑,答案随口而来: 1.GET在浏览器回退时是无害的,而POST会再次提交请求. 2.GET请求会被浏览器主动cache,而POST不会,除非手动设置. 3 ...