前言:

一直致力于提高开发效率降低项目耦合,今天想抽空学习一下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. 入坑系列之HAProxy负载均衡

    在大型系统设计中用代理在负载均衡是最常见的一种方式,而相对靠谱的解决方案中Nginx.HAProxy.LVS.F5在各大场中用得比较普遍,各有各的优势和使用场景,由于本次要使用到TCP,因此Nginx ...

  2. 每天一个Linux命令 2

    wc 命令用于统计指定文本的行数.字数.字节数.格式为“wc [参数] 文本” . 参数                                                       作 ...

  3. CentOS 7安装配置FTP服务器

    CentOS 7下FTP服务器的安装配置. 假设我们有以下要求 路径 权限 备注 /ftp/open 公司所有人员包括来宾均可以访问 只读 /ftp/private 仅允许Alice.Jack.Tom ...

  4. KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架之koahub-body-res

    koahub body res Format koa's respond json. Installation $ npm install koahub-body-res Use with koa v ...

  5. Internal Server Error with LAMP

    文章出自:http://blog.csdn.net/lipei1220/article/details/8186406 我的问题:  500  添加 .htaccess 后刷新网页就出现错误. 原因为 ...

  6. Django通用视图执行过程

    使用通用视图后,Django请求处理过程(以ListView为例):在我们自定义的视图中: class IndexView(ListView): template_name = 'blog/index ...

  7. noip2008(最优贸易)

    C 国有 n 个大城市和 m 条道路,每条道路连接这 n 个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 m 条道路中有一部分为单向通行的道路,一部分为双向通行的道路,双向通行的道 ...

  8. 【一】Swift 3.0 新浪微博项目实战 -整体框架搭建

    最近要接手swift,所以找了个视频跟着做一下实战项目,在此记录一下过程和心得 框架搭建和目录拆分 关键词:MVVM 架构,桥接文件 桥接文件用于引入OC的头文件,Swift就可以正常使用(宏除外). ...

  9. 简单的android启动跳转页面

    java代码示例: package com.rcl; import android.app.Activity;import android.content.Intent;import android. ...

  10. Windows 10 Creaters Update 画中画模式和窗口高斯模糊

    在Windows 10 Creaters Update中,可以给窗口设置高斯模糊了,只要几行代码! <Grid Loaded="Grid_Loaded"> <Gr ...