前言:

一直致力于提高开发效率降低项目耦合,今天想抽空学习一下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. Extjs中grid前端分页使用PagingMemoryProxy【二】

        在项目中遇到Grid前端分页,本人也是刚接触extjs没多久,为了实现效果,一直找了很久才实现出来,对于代码中的一些也不能详细的说明出来, 不知道能不能帮助到遇到同样问题的朋友,所以将例子代码 ...

  2. 使用python操作InfluxDB

    环境: CentOS6.5_x64InfluxDB版本:1.1.0Python版本 : 2.6 准备工作 启动服务器 执行如下命令: service influxdb start 示例如下: [roo ...

  3. struts.xml语法

    <!-- 1. struts.xml配置常量, 用来覆盖struts.properties中的默认常量配置 一般情况下, 这个配置放在struts.xml中, 不要放在各个模块的xml中. co ...

  4. ubuntu中文输入问题

    因为硬盘版的一些缺陷,我狠心的把windows8覆盖为ubuntu 13.10,用u盘安装,除了分区稀里糊涂的还不知到怎么分,其他问题就是汉字的输入问题了,因为之前选了english-US 后来就没有 ...

  5. Linux 修改时区 不用重启

    1.cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 2.使用tzselect命令,根据提示选择 3.使用date查看是否修改正确 4.运行hwc ...

  6. Java学习笔记 11/15:一个简单的JAVA例子

    首先来看一个简单的 Java 程序. 来看下面这个程序,试试看是否看得出它是在做哪些事情! 范例:TestJava.java   // TestJava.java,java 的简单范例  public ...

  7. Python中的日期和时间

    感觉C语言作为一门编程的入门语言还是很好的,相比较之下,Python为代表的一些语言,适合很多非计算机专业的编程入门学习. Python 日期和时间 Python 程序能用很多方式处理日期和时间,转换 ...

  8. Chapter 3. Programming with RDDs

     Programming with RDDs This chapter introduces Spark's core abstraction for working with data, the r ...

  9. 搭建高可用mongo集群3.4版本

    搭建高可用mongo集群3.4版本 说在开始之前:在搭建这个环境之前,已经有了一个师兄搭好的环境,虽然一样很棒,但是没有经过自己的手出来的东西,还是不属于自己,所以摸索着自己搭建一个吧,好巧不巧的是, ...

  10. 如何记录selenium自动化测试过程中接口的调用信息

    上一篇博客,我写了python自动化框架的一些知识和粗浅的看法,在上一篇中我也给自己提出一个需求:如果记录在测试过程中接口的调用情况?提出这个需求,我觉得是有意义的.你在测试过程中肯定会遇到一些莫名其 ...