前言:

一直致力于提高开发效率降低项目耦合,今天想抽空学习一下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设计模式实现项目解耦的更多相关文章

  1. Android学习探索之Java 8 在Android 开发中的应用

    前言: Java 8推出已经将近2年多了,引入很多革命性变化,加入了函数式编程的特征,使基于行为的编程成为可能,同时减化了各种设计模式的实现方式,是Java有史以来最重要的更新.但是Android上, ...

  2. 学习RxJava+Retrofit+OkHttp+MVP的网络请求使用

    公司的大佬用的是这一套,那我这个菜鸟肯定要学习使用了. 我在网上找了很多文章,写的都很详细,比如 https://www.jianshu.com/u/5fd2523645da https://www. ...

  3. android学习日记28--Android中常用设计模式总结

    一.综述 设计模式,根据前人经验总结出常见软件工程问题的解决思想套路.GoF一共归纳了23种设计模式,当然还有人扩充,不止这些.设计模式主要利用面向对象语言的特性,而android 的设计主要用JAV ...

  4. android学习日记27--Dialog使用及其设计模式

    1.Dialog概述 对话框一般是一个出现在当前Activity之上的一个小窗口,处于下面的Activity失去焦点, 对话框接受所有的用户交互. 对话框一般用于提示信息和与当前应用程序直接相关的小功 ...

  5. Android学习探索之本地原生渲染 LaTeX数据公式

    前言: 一直致力于为公司寻找更加高效的解决方案,作为一款K12在线教育App,功能中难免会有LaTeX数学公式的显示需求,这部分公司已经实现了此功能,只是个人觉得在体验和效率上还是不太好,今天来聊一下 ...

  6. Android学习探索之App多渠道打包及动态添加修改资源属性

    前言: 关于Android渠道打包是一个比较老的话题,今天主要记录总结一下多渠道打包以及如果动态配置修改一些资源属性.今天以公司实际需求为例进行演示,由于项目复用很多公共的业务组件,而且业务组件之间的 ...

  7. Android为TV端助力 MVP设计模式!

    实现原理: MainActivity 用来更新UI,和显示业务逻辑的结果! LoginPresenterCompl 用来处理 业务逻辑 ILoginPresenter 业务处理类抽象出来的接口 ILo ...

  8. Android学习笔记(一)——新建一个项目

    //此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! 1.打开Android Studio时出现以下界面,点击”start a new Android Studio ...

  9. android学习日记03--常用控件Dialog

    常用控件 9.Dialog 我们经常会需要在Android界面上弹出一些对话框,比如询问用户或者让用户选择.这些功能我们叫它Android Dialog对话框 对话框,要创建对话框之前首先要创建Bui ...

随机推荐

  1. 简单聊聊TestNG中的并发

    前言 最近在做项目里的自动化测试工作,使用的是TestNG测试框架,主要涉及的测试类型有接口测试以及基于业务实际场景的场景化测试.由于涉及的场景大多都是大数据的作业开发及执行(如MapReduce.S ...

  2. 算法模板——Dinic网络最大流 1

    实现功能:同sap网络最大流 今天第一次学Dinic,感觉最大的特点就是——相当的白话,相当的容易懂,而且丝毫不影响复杂度,顶多也就是代码长个几行 主要原理就是每次用spfa以O(n)的时间复杂度预处 ...

  3. 多个Activity交互的生命周期:

    一.多个Activity交互的生命周期: A Activity打开B Activity的时候:        A Activity                    B Activity     ...

  4. spring或springmvc自动生成applicationcontext.xml或springmvc文件(此文转载和借鉴多篇文章)

    在用spring或者springmvc框架进行开发时,编辑applicationcontext.xml等配置文件是必不可少的,在eclipse中打开applicationcontext.xml通常是这 ...

  5. android 透明状态栏方法及其适配键盘上推(二)

    在上一篇文章中介绍了一种设置透明状态栏及其适配键盘上推得方法.但是上一篇介绍的方法中有个缺点,就是不能消除掉statusbar的阴影.很多手机如(三星,Nexus都带有阴影).即使我用了: <a ...

  6. 浅谈HashMap的内部实现

    权衡时空 HashMap是以键值对的方式存储数据的. 如果没有内存限制,那我直接用哈希Map的键作为数组的索引,取的时候直接按索引get就行了,可是地价那么贵,哪里有无限制的地盘呢. 如果没有时间限制 ...

  7. Jsonql——给RESTful API插上一对翅膀

    RESTful API是目前比较成熟的一套互联网应用程序的API设计理论,规范了服务端资源的定义及访问.我们团队服务端就采用了RESTful. 可是在现实开发过程中,还是有些问题. 客户端在获取资源的 ...

  8. 解决华为手机不打印Log信息的问题

    在之前安装了Android Studio后,发现了一个很苦恼的事情,就是在程序中的写Log语句,不能正常的在Logcat中打印出来,这对于解决程序bug真是一刀切断,让人无从下手,在各种尝试后,首先我 ...

  9. iOSiOS开发之数据存储之NSKeyedArchiver

    1.概述 NSKeyedArchiver归档和plist文件存储不同的是NSKeyedArchiver可以直接保存对象.如果对象是NSString.NSDictionary.NSArray.NSDat ...

  10. RecyclerView中装饰者模式应用

    近段时间一直在加班,在赶一个项目,现在项目接近尾声,那么需要对过去一段时间工作内容进行复盘,总结下比较好的解决方案,积累一些经验,我认为的学习方式,是「理论-实践-总结-分享」,这一种很好的沉淀方式. ...