网上关于MVP的博客不少,本笔记做为学习google提供的MVP的学习笔记,html
谷歌开发中国中文内站:https://developers.google.cn/java
在网站上找到Android,点击进入后能够找到一些开发的说明帮助,谷歌也提供了一些开发模板,浏览示例代码里,能够找到 Google Samples page on GitHub。里面提供了一些开发demo,例如本文里的MVP开发模式就能够从找android-architecture 找详细的demo。android
网上也有不少对于官方MVP demo解读的文章。例如这篇文章就有比较详细的说明http://www.cnblogs.com/mengdd/p/5988104.htmlgit
如下是MVC的框架图:github
如下是MVP的框架图:app
借用网上的图对于MVC与MVP的区别, 在MVC框架中,View是能够直接读取Model模型中的数据的,Model模型数据发生改变是会通知View数据显示发生相应的改变,致使View既须要负责视图的显示和数据的处理。而在MVP中Model和View之间的没有任何联系,是两个彻底独立的模块,当Model模型发生数据改变时,经过Presenter通知View视图发生相应的UI改变,View层只须要接受 Presenter的数据,并在视图上作相应的改变。框架
Sample | Description | |
---|---|---|
todo‑mvp | Demonstrates a basic Model‑View‑Presenter (MVP) architecture and provides a foundation on which the other samples are built. This sample also acts as a reference point for comparing and contrasting the other samples in this project. | |
todo‑mvp‑loaders | Fetches data using the Loaders API. | |
todo‑databinding | Uses the Data Binding Library. | |
todo‑mvp‑clean | Uses concepts from Clean Architecture. | |
todo‑mvp‑dagger | Uses Dagger2 to add support for dependency injection. | |
todo‑mvp‑contentproviders | Based on the todo-mvp-loaders sample, this version fetches data using the Loaders API, and also makes use of content providers. | |
todo‑mvp‑rxjava | Uses RxJava to implement concurrency, and abstract the data layer. |
Sample | Description |
---|---|
dev‑todo‑mvp‑tablet | Adds a master and detail view for tablets. |
dev‑todo‑mvvm‑databinding | Based on the todo-databinding sample, this version incorporates the Model‑View‑ViewModel architecture. |
For information about planned samples, see "New sample" issues.less
External samples are variants that may not be in sync with the rest of the branches in this repository.mvvm
Sample | Description |
---|---|
todo‑mvp‑fragmentless | Uses View objects instead of Fragment objects. |
todo‑mvp‑conductor | Uses the Conductor framework to refactor the app to use a single Activity architecture. |
官方中对MVP有一个比较详细的demo代码,一个完整的数据增删改查的过程。ide
共有11个完整的示例,从简单到复杂,一步一步的说明MVP如何的工做。
先看第一个todo‑mvp工程,demo分四个界面,
1.列表页,具体功能有A:显示所有Task列表,B:显示状态为Active状态的Task列表,C:显示状态为Completed状态的Task列表 ,D:刷新列表,E:清除Completed状态的数据。
2.详情页,修改页,两个页面是同一个,能够从详情状态变成修改状态,并有删功能。
3.建立页,建立一个task,
4.统计页 ,统计Active状态的Task和Completed状态的Task有多少个。
先分析列表页的View, Presenter和Data三层接口
Data层接口
public interface TasksDataSource { interface LoadTasksCallback { void onTasksLoaded(List<Task> tasks); void onDataNotAvailable(); } interface GetTaskCallback { void onTaskLoaded(Task task); void onDataNotAvailable(); } void getTasks(@NonNull LoadTasksCallback callback);//获取Tasks列表 void saveTask(@NonNull Task task);//保存一个tasks void completeTask(@NonNull Task task);//把一个task标记为completed void clearCompletedTasks();//清除completed状态的task void deleteTask(@NonNull String taskId);//删除一个task void refreshTasks();//刷新列表。 一系列的增删改查的方法....省略,具体能够查看官方提供的完整demo. }
TasksDataSource 的子类除了TasksLocalDataSource,TasksRemoteDataSource外,还有一个TasksRepository,TasksRepository组合了TasksLocalDataSource,TasksRemoteDataSource两个实例,TasksRepository负责与Presenter层交互,做为P层与Data层交互的桥梁, TasksLocalDataSource,TasksRemoteDataSource 并不直接与Presenter层交互。TasksRepository是一个单例。
Presenter与View层
这两层都写在一个叫TasksContract的接口类中
public interface BaseView<T> { void setPresenter(T presenter); }
public interface TasksContract { interface View extends BaseView<Presenter> { /* 与数据相关的一些方法*/ void showAddTask(); void showTaskDetailsUi(String taskId); void showTasks(List<Task> tasks); /*告知Presenter层View层的一些状态相关的方法。*/ boolean isActive(); /*单纯的界面显示方法*/ void showFilteringPopUpMenu(); ...省略,一系列界面的显示与提示。具体请查看官方完整代码。 } interface Presenter extends BasePresenter { /**与界面交互的一些方法*/ void result(int requestCode, int resultCode); void addNewTask(); /*对数据增删改查的一系列操做*/。 void loadTasks(boolean forceUpdate); void openTaskDetails(@NonNull Task requestedTask); void completeTask(@NonNull Task completedTask); void activateTask(@NonNull Task activeTask); void clearCompletedTasks(); /**一些与数据相关的和界面相关的过程变量*/ void setFiltering(TasksFilterType requestType); TasksFilterType getFiltering(); } }
由上面的接口定义可知,
View层定义是一些与数据相关的并与界面相关的一些方法,例如
或者是一些Presenter层与View层的交互时,Presenter须要知道的View层的一些生命周期状态相关的方法。例如
或者单纯的界面的提示的一些方法如void showNoTasks()
一些与数据操做无关的方法,通常不定义在View层的接口里,如从列表页跳转到统计页就是与数据操做无关的方法,相应的由于View层不处理数据,因此View层只处理动做与数据展现,Presenter层处理数据相关的逻辑。
Data层的实例建立须要的对象与参数
private TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource, @NonNull TasksDataSource tasksLocalDataSource) { mTasksRemoteDataSource = checkNotNull(tasksRemoteDataSource); mTasksLocalDataSource = checkNotNull(tasksLocalDataSource);
View层
todo‑mvp的官方示例中,View层就是一个实现了TasksContract.View接口的Fragment,和普通的Fragment并无什么的不一样
public static TasksFragment newInstance() { return new TasksFragment(); }
Presenter层的实例建立须要的对象与参数
public TasksPresenter(@NonNull TasksRepository tasksRepository, @NonNull TasksContract.View tasksView) { mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null"); mTasksView = checkNotNull(tasksView, "tasksView cannot be null!"); mTasksView.setPresenter(this); }
从上面的构造方法中能够知道。
Presenter用成员变量组合的方式, 持有 了View层实例与Data数据层的实例,
而 mTasksView.setPresenter(this);这句也代表了View层也持有Presenter的引用
数据层是独立的一层,只提供一个单供给外部对象用。这样就实现了
界面与数据逻辑操做的分离,View层只关注与界面的展现。
下面分析一下,数据查、改、增、删操做时,MVP三层工做的过程。
用一个加载所有Task列表的过程来讲明MVP对数据查找与展现的过程。
获取所有Task的显示和获取Active状态和Completed状态的Task列表显示是相同的过程,只是在
View层在调用 Presenter层的void loadTasks(boolean forceUpdate);前先调用了Presenter的void setFiltering(TasksFilterType requestType);,加载数据时,会判断当前的TasksFilterType 并加载相应类型的数据。
Task状态的改变等操做与加载列表显示的过程大同小异。
官方todo‑mvp项目我的总结。
1.定义数据层,View层,和Presenter接口,View层接口通常定义一些与数据展现有关的方法和界面上的操做会引发数据变化须要Presenter逻辑处理数据后过才能展现的接口方法。
2.View层和Presenter层相互持有对方的实例引用,数据层只被Presenter层持有,不被View层持有,全部须要处理数据的逻辑都放在Presenter层处理。这样就达到了View层与数据层分离。