作者:谭东

先给个MVP的出处链接:https://github.com/googlesamples/android-architecture/,出处就是google在github上的一个架构的开源例子,里面有个todo-mvp的sample项目,大概的展示了下它们的架构设计,也就是这个todo-mvp例子项目的架构:https://github.com/googlesamples/android-architecture/tree/todo-mvp/。

这只是他们认为比较好的架构方式,被传开了了,也就出现了MVP模式。但是并不一定这个模式就非常好,只不过有它的好处的初衷:想让结构更加的清晰,逻辑耦合度降低。但相对来说也使开发变得逻辑复杂了些,一般大型的项目推荐使用,看你的需求和权衡了。

之前也看了一些MVP的文章,没有太认真看,也是云里雾里。后来索性抽空一上午的时间,直接看官方的todo-mvp的例子源码,一点点分析整理google的mvp的设计的思路和流程。这个Demo演示了谷歌github例子的Model-View-Presenter(MVP)的架构设计,不过说实话,官方的demo写的有点乱,类命名、方法命名等很不清晰。总体来说还好,下午的时间就按照这个mvp的架构规范重新写了一个版本的todo-mvp。原版的todo-mvp用的是sqlite,涉及到了RoomDatabase。让注重mvp阅读人看起来很乱,容易分散重点。所以我这里使用sharedpreferences替换了sqlite的数据增删改查。 整体说来,官方的例子选择的还算容易理解,实现的功能就是列表展示本地存储的任务Task数据。有增加一条、删除一条、获取一条、获取全部任务的功能。

先看原版的实现设计图:

淡绿色部分就是View和Presenter部分的双向交互,左侧白底部分的就是Model部分的逻辑,可以看出整个MVP就是Model和Presenter的交互及View和Presenter的双向交互,而View和Model之间并没有直接的交互,这也就避免了耦合吧。

下面这个是我改过重写的demo的实现,把SQLite换成了SharedPreference,去除了本地和网络的任务的判断。

我这里以todo-mvp的我精心改版整理后的项目进行分析讲解,MVP的整体架构分析:

官方的demo基本上是按照功能分类的,把很多类都混在一起了,我这里的结构整理,相对清晰一些。

先说MVP的Model:

Model里先有实体,这里是Task:

/*** Created by Tandong on 2018/4/2.* MVP中某个M的基础实体类*/public class Task {private String id;private String date;private String title;private String content;private boolean completed;public String getId() {return id;}public void setId(String id) {this.id = id;}public String getDate() {return date;}public void setDate(String date) {this.date = date;}public String getTitle() {return title;}public void setTitle(String title) {this.title = title;}public String getContent() {return content;}public void setContent(String content) {this.content = content;}public boolean isCompleted() {return completed;}public void setCompleted(boolean completed) {this.completed = completed;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Task task = (Task) o;return id.equals(task.id);}
}

以及操作Task实体的定义的方法,TaskDao,它的作用就是预先定义对外暴漏操作Task的接口方法:

/*** Created by Tandong on 2018/4/2.* 对应的Task的Model的主要方法接口定义类*/public interface TaskDao {void getTasks(@NonNull LoadTasksCallback callback);void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);void saveTask(@NonNull Task task);void refreshTasks();void deleteAllTasks();void deleteTask(@NonNull Task task);interface LoadTasksCallback {void onTasksLoaded(List<Task> tasks);void onDataNotAvailable();}interface GetTaskCallback {void onTaskLoaded(Task task);void onDataNotAvailable();}
}

之后,再实现TaskDao里的定义的接口方法,也就是要有TaskImpl实现类:

/*** Created by Tandong on 2018/4/2.* Task的Model的接口方法的具体实现,采用单例模式*/public class TaskDaoImpl implements TaskDao {private static TaskDaoImpl INSTANCE = null;private static final int SERVICE_LATENCY_IN_MILLIS = 500;private static List<Task> TASKS_SERVICE_DATA = null;// 防止直接实例化private TaskDaoImpl() {}/*** 单例模式创建TaskDaoImpl** @return*/public static TaskDaoImpl getInstance() {if (INSTANCE == null) {INSTANCE = new TaskDaoImpl();}return INSTANCE;}/*** 销毁回收实例对象*/public static void destroyInstance() {INSTANCE = null;}@Overridepublic void getTasks(@NonNull final LoadTasksCallback callback) {//逻辑的具体实现,这里获取数据Handler handler = new Handler();handler.postDelayed(new Runnable() {@Overridepublic void run() {TASKS_SERVICE_DATA = Utils.getTasksFromSp();callback.onTasksLoaded(TASKS_SERVICE_DATA);}}, SERVICE_LATENCY_IN_MILLIS);}@Overridepublic void getTask(@NonNull String taskId, @NonNull final GetTaskCallback callback) {int position = 0;TASKS_SERVICE_DATA = Utils.getTasksFromSp();for (int i = 0; i < TASKS_SERVICE_DATA.size(); i++) {if (TASKS_SERVICE_DATA.get(i).getId().equals(taskId)) {position = i;}}//逻辑的具体实现final Task task = TASKS_SERVICE_DATA.get(position);Handler handler = new Handler();handler.postDelayed(new Runnable() {@Overridepublic void run() {callback.onTaskLoaded(task);}}, SERVICE_LATENCY_IN_MILLIS);}@Overridepublic void saveTask(@NonNull Task task) {//逻辑的具体实现TASKS_SERVICE_DATA.add(task);Utils.addTaskToSp(task);}@Overridepublic void refreshTasks() {//逻辑的具体实现TASKS_SERVICE_DATA = Utils.getTasksFromSp();}@Overridepublic void deleteAllTasks() {//逻辑的具体实现TASKS_SERVICE_DATA.clear();Utils.deleteAllTaskToSp();}@Overridepublic void deleteTask(@NonNull Task task) {//逻辑的具体实现Utils.deleteTaskToSp(task);}
}

那么可以看出,Model里一般有3个类,以这个todo-mvp例子来说,有实体类Task,接口方法类TaskDao,实现类TaskImpl。

接着定义我们的View:

根据情况,我们可以定义一个父类的View叫BaseView,当然直接写一个View也没问题。

这个View的类里我们定义好我们的Activity或者Fragment界面需要交互操作的一些方法。

interface View extends BaseView<Presenter> {/*** 这里定义操作View界面相关的回调方法*/void setLoadingIndicator(boolean show);void showTasks(List<Task> tasks);void showAddTaskOk(Task task);void showTaskDetailsUi(String taskId);void showLoadingTasksError();void showNoTasks();boolean isActive();void showClearedAllTaskOk();void showClearedTaskOk(Task task);}

然后定义Presenter,Presenter的中文意思是主持人,顾名思义也就是整个Model和View的调度和指挥者。Presenter就是把Model的TaskImpl类和View的View类关联结合起来。里面定义的方法也是对应View和Model相连接调用的中间件接口方法,类似于一个中间转接接口。

    interface Presenter extends BasePresenter {/*** 这里定义操作加载处理数据的相关回调方法*/void loadTasks(boolean showLoading);void addNewTask(@NonNull Task task);void openTaskDetails(@NonNull Task task);void clearAllTasks();void clearTask(@NonNull Task task);}

google官方的todo-mvp的例子中间又加了一层,Contract类,就是一个连接关联类Contract,把View和Presenter关联起来。

/*** Created by Tandong on 2018/4/2.* 一个连接关联类Contract,把View和Presenter关联起来*/public interface TasksContract {interface View extends BaseView<Presenter> {/*** 这里定义操作View界面相关的回调方法*/void setLoadingIndicator(boolean show);void showTasks(List<Task> tasks);void showAddTaskOk(Task task);void showTaskDetailsUi(String taskId);void showLoadingTasksError();void showNoTasks();boolean isActive();void showClearedAllTaskOk();void showClearedTaskOk(Task task);}interface Presenter extends BasePresenter {/*** 这里定义操作加载处理数据的相关回调方法*/void loadTasks(boolean showLoading);void addNewTask(@NonNull Task task);void openTaskDetails(@NonNull Task task);void clearAllTasks();void clearTask(@NonNull Task task);}}

这一层我觉的可以调整,可有可无。把这个写成一个View就可以。

然后定义编写我们的真正的Presenter实现类,TasksPresenter类。

/*** Created by Tandong on 2018/4/2.* Presenter的业务真正实现,监听用户UI操作,回调和更新数据给UI*/public class TasksPresenter implements TasksContract.Presenter {private final TaskDaoImpl taskDaoImpl;private final TasksContract.View tasksView;public TasksPresenter(@NonNull TaskDaoImpl taskDaoImpl, @NonNull TasksContract.View tasksView) {this.taskDaoImpl = Utils.checkNotNull(taskDaoImpl, "tasksRepository cannot be null");this.tasksView = Utils.checkNotNull(tasksView, "tasksView cannot be null!");this.tasksView.setPresenter(this);}@Overridepublic void start() {loadTasks(true);}@Overridepublic void loadTasks(boolean showLoading) {toLoadTasks(showLoading);}/*** 添加数据操作*/@Overridepublic void addNewTask(@NonNull Task task) {//操作ModeltaskDaoImpl.saveTask(task);//操作ViewtasksView.showAddTaskOk(task);}@Overridepublic void openTaskDetails(@NonNull Task requestedTask) {Utils.checkNotNull(requestedTask, "requestedTask cannot be null!");tasksView.showTaskDetailsUi(requestedTask.getId());}/*** 删除全部数据操作*/@Overridepublic void clearAllTasks() {//操作ModeltaskDaoImpl.deleteAllTasks();//操作ViewtasksView.showClearedAllTaskOk();}/*** 删除单条数据操作** @param task*/@Overridepublic void clearTask(@NonNull Task task) {//操作ModeltaskDaoImpl.deleteTask(task);//操作ViewtasksView.showClearedTaskOk(task);}private void toLoadTasks(final boolean showLoadingUI) {if (showLoadingUI) {//显示加载中进度条布局tasksView.setLoadingIndicator(true);}taskDaoImpl.getTasks(new TaskDao.LoadTasksCallback() {@Overridepublic void onTasksLoaded(List<Task> tasks) {// The view may not be able to handle UI updates anymoreif (!tasksView.isActive()) {return;}if (showLoadingUI) {//隐藏加载中进度条tasksView.setLoadingIndicator(false);}processTasks(tasks);}@Overridepublic void onDataNotAvailable() {// The view may not be able to handle UI updates anymoreif (!tasksView.isActive()) {return;}tasksView.showLoadingTasksError();}});}private void processTasks(List<Task> tasks) {if (tasks.isEmpty()) {// Show a message indicating there are no tasks for that filter type.processEmptyTasks();} else {//加载完毕后回调给View进行显示逻辑处理tasksView.showTasks(tasks);}}private void processEmptyTasks() {tasksView.showNoTasks();}}

可以看出,这个Presenter实现类,实现了之前定义的Presenter接口里的方法,监听用户UI操作,回调和更新数据给UI。里面含有两个大类:TaskDaoImpl这个Model实现类和TasksContract.View这个View类,也就是把Model和View进行了关联和调度。从每个方法里也可以看出,每个方法基本上都有Model方法的调用和View的相应的操作调用。

好了,我们的Model、View、Presenter都写好了。接下来就是Activity或Fragment界面的调用了。

todo-mvp的demo里是Activity里调用了TaskFragment进行View的操作。那看下TaskFragment里的具体逻辑,TaskFragment先实现之前View里调用的接口TasksContract.View:

/*** Created by Tandong on 2018/4/2.* Fragment实现View的接口方法回调*/public class TaskFragment extends BaseFragment implements TasksContract.View, OnItemCallBack {@Bind(R.id.rv)RecyclerView recyclerView;@Bind(R.id.tv_tips)TextView tv_tips;private TaskAdapter taskAdapter;private LinearLayoutManager linearLayoutManager;private TasksContract.Presenter presenter;public TaskFragment() {// Requires empty public constructor}public static TaskFragment newInstance() {return new TaskFragment();}@Overridepublic void onCreate(@Nullable Bundle savedInstanceState) {super.onCreate(savedInstanceState);}@Nullable@Overridepublic View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {View root = inflater.inflate(R.layout.fragment_tasks, container, false);ButterKnife.bind(this, root);return root;}@Overridepublic void onActivityCreated(@Nullable Bundle savedInstanceState) {super.onActivityCreated(savedInstanceState);linearLayoutManager = new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false);taskAdapter = new TaskAdapter(getActivity(), Utils.getTasksFromSp());taskAdapter.setOnItemCallBack(this);recyclerView.setLayoutManager(linearLayoutManager);recyclerView.setAdapter(taskAdapter);}@Overridepublic void onResume() {super.onResume();presenter.start();}@Overridepublic void setPresenter(TasksContract.Presenter presenter) {this.presenter = Utils.checkNotNull(presenter);}@Overridepublic void setLoadingIndicator(boolean show) {if (show) {tv_tips.setVisibility(View.VISIBLE);tv_tips.setText("加载中...");} else {tv_tips.setVisibility(View.GONE);}}@Overridepublic void showTasks(List<Task> tasks) {//view的操作具体逻辑实现taskAdapter.setDatas(tasks);}@Overridepublic void showAddTaskOk(Task task) {//view的操作具体逻辑实现showToast("添加任务成功~");taskAdapter.addData(task);}@Overridepublic void showTaskDetailsUi(String taskId) {//view的操作具体逻辑实现}@Overridepublic void showLoadingTasksError() {//view的操作具体逻辑实现tv_tips.setVisibility(View.VISIBLE);tv_tips.setText("加载失败~");}@Overridepublic void showNoTasks() {//view的操作具体逻辑实现tv_tips.setVisibility(View.VISIBLE);tv_tips.setText("没有数据~");}@Overridepublic boolean isActive() {//view的操作具体逻辑实现return isAdded();}@Overridepublic void showClearedAllTaskOk() {//view的操作具体逻辑实现tv_tips.setVisibility(View.VISIBLE);tv_tips.setText("没有数据~");}@Overridepublic void showClearedTaskOk(Task task) {taskAdapter.removeData(task);}@Overridepublic void onItemLongClick(View v, int posiotion) {showToast("长按移除  " + posiotion);presenter.clearTask(taskAdapter.getTasks().get(posiotion));}@Overridepublic void onItemClick(View v, int position) {Task task = taskAdapter.getTasks().get(position);showToast(position + "  " + task.getTitle() + "  " + task.getContent());}
}

然后在实现的回调方法里,把返回的数据或者状态进行相应的操作和UI上的响应。也可以操作presenter里的一些方法。

那么整合MVP的todo-mvp的官方例子基本上这样,官方的todo-mvp里的功能多一点,有展示、添加、详情等分类。不过流程和操作都类似,MVP的官方例子就给大家讲解这么多。

整理后的Demo的github地址:https://github.com/jaychou2012/MVPDemo-todo-mvp

Android MVP模式介绍和讲解相关推荐

  1. Android MVP模式 简单易懂的介绍方式

    主要学习这位大神的博客:简而易懂 Android MVP模式 简单易懂的介绍方式 https://segmentfault.com/a/1190000003927200 转载于:https://www ...

  2. Android MVP模式简单易懂的介绍方式 (一)

    Android MVP模式简单易懂的介绍方式 (一) Android MVP模式简单易懂的介绍方式 (二) Android MVP模式简单易懂的介绍方式 (三) 最近正在研究Android的MVP模式 ...

  3. android mvp模式例子_ANDROID MVP 模式 简单易懂的介绍方式

    Android MVP Pattern Android MVP 模式1 也不是什么新鲜的东西了,我在自己的项目里也普遍地使用了这个设计模式.当项目越来越庞大.复杂,参与的研发人员越来越多的时候,MVP ...

  4. Android MVP模式 解析JSON 显示到ListView上

    Android MVP模式 解析JSON 显示到ListView上 有关MVP模式的介绍,这里不作详细解释,稍后会更新MVP设计模式,请等待链接-- 简述本次的主要功能实现: 通过mvp设计模式,(M ...

  5. Android MVP模式学习

    Android MVP模式学习 参考: Android MVP 开发模式有哪些优缺点?: https://www.zhihu.com/question/35185744 MVP 模式简单易懂的介绍方式 ...

  6. android mvp 利弊,android mvp模式有什么弊端 - 什么是android mvp模式,android mvp模式有什么弊端...

    android mvp模式有什么弊端 才开始学习使用MVP时,看到大家说了很多MVP的优点,代码复用,条理清晰等等.不过我改下来发现,MVP在我看来,最大的优点还是代码解耦,逻辑清晰,至于代码复用,暂 ...

  7. android mvp模式例子_Android中mvp模式使用实例详解

    MVP 是从经典的模式MVC演变而来,它们的基本思想有相通的地方:Controller/Presenter负责逻辑的处理,Model提供数据,View负 责显示.作为一种新的模式,MVP与MVC有着一 ...

  8. android mvp模式鸿洋,Android上的MVP模式

    什么是MVP? MVP模式可以分离显示层和逻辑层,所以功能接口如何工作与功能的展示可以实现分离,MVP模式理想化地可以实现同一份逻辑代码搭配不同的显示界面.首先要澄清就是MVP不是一个结构化的模式,它 ...

  9. Android MVP模式规范

    前言 首先,这篇文章不在讲解什么是mvp模式,如果需要请自行搜索mvp模式文章了解.这个文章里我只记录mvp模式的创建和mvp各自层的界限.另外这个博客属于个人使用mvp模式后一些经验总结与记录.并不 ...

最新文章

  1. 低调的苹果罕见发表论文,揭开自动驾驶汽车技术的冰山一角
  2. linux换服务器登录插件,Linux服务器登录、注销 用户和用户组管理
  3. threadlocal内存泄露_ThreadLocal 简介
  4. android ApiDemos学习1 主界面动态ListView显示
  5. 欢迎大家多来关注下!
  6. 今天在网上看到一个帖子,怎么样锻炼自己的大脑
  7. 计算机互联网行业高校,9家互联网巨头最青睐的重点大学汇总,网友:比各种排名强太多了...
  8. 泛微对协同管理的定义
  9. libevent 接收TCP连接
  10. OpenMAX IL介绍与其体系
  11. Unix环境高级编程的学习环境的搭建
  12. PHP多功能自动发卡平台源码带手机版 带多套商户模板
  13. java解析Excel文件
  14. iOS字体大小适配的几种方法
  15. java程序员常用的快捷键
  16. 小新pro13睡眠后无法唤醒_小新air12、air13、air13pro睡眠后无法唤醒的调试方法
  17. 计算机怎么加项目符号,2010年职称计算机:添加项目符号
  18. 网络带宽和吞吐量throughput的关系
  19. Tornadao—模板语法(函数)
  20. 离轴高数值孔径抛物面反射镜的聚焦

热门文章

  1. iverilog搭建简易仿真平台
  2. Ariel India旨在宣扬共同承担家务的新影片《See Equal》引发热烈反响
  3. 毕业设计 英雄联盟数据分析与预测 -大数据分析 可视化 机器学习
  4. 走进WebAssembly
  5. Revit土建翻模:梁端点连接方式的操作及梁生成
  6. 全国计算机技术与软件专业技术资格(水平)考试【软件评测师】-考试内容总结(一)计算机系统构成及硬件基础知识...
  7. 线程(六)之LOCK和synchronized
  8. windows下安装docker详细步骤
  9. O2O外卖网“开吃吧”投百万年流水过亿
  10. 火狐谷歌chrome等浏览器支持一些css滤镜