MVP简介
MVP 对应一个应用分成三个基础的部分
Model层 负责处理应用的数据部分
View层 负责应用的界面绘制和用户交互
Presenter计算层 负责连接View和Model,也负责操控View
MVP 的一些基础规则
- View只负责根据Presenter的计算结果展示对应的界面
- View将用户的动作反馈给Presenter
- View永远不与Model交互
- Presenter负责解析View的请求并计算后通知View显示
- Model负责从本地或者网络拉取数据
todo-mvp
这个例子中每个界面由以下四个部分实现
1. Contract 定义View和Presenter之间的联系,其实是定义所有View和Presenter的相关操作的接口
2. Activity 创建Presenter和Fragment
3. Fragment mvp中的view层,实现了Contract中的View接口,负责界面的展示
4. Presenter 实现Contract中对应的Presenter接口
代码实现
首先看看两个View和Presenter的两个基类BaseView
和BaseView
,都只有一个方法,所有的View都实现BaseView,通过setPresenter可以让View持有Presenter,Presenter都实现BasePresenter,在start方法中调用初始化数据的操作。
public interface BaseView<T> {
void setPresenter(T presenter);
}
public interface BasePresenter {
void start();
}
demo是一个简单的备忘录,每个文件夹是一个界面,这个demo中有四个界面,添加和编辑界面,统计界面,任务详情,任务列表,以任务详情页为例
可以看到界面上的功能有 编辑,删除,完成(CheckBox选中),任务置为活跃(CheckBox取消选中),可以抽象出对应的Presenter四个方法,见TaskDetailContract.Presenter
根据task展示的各种状态View抽象出的接口见TaskDetailContract.View
,在fragment的resume方法中调用present的start方法,委托presenter开始准备数据,presenter受到委托后调用model层的方法获取数据,并调用View的setLoadingIndicator方法将View置成加载中的状态,等数据加载完成后根据是否有数据决定调用view的显示数据方法还是空页面方法,这样就实现了之前所说的view只绘制相应界面,presenter决定显示什么界面,model只负责获取数据,但时presenter决定什么时候获取,用户其他的操作也是和加载数据一样按照上述的流程
/**
* This specifies the contract between the view and the presenter.
*/
public interface TaskDetailContract {
interface View extends BaseView<Presenter> {
void setLoadingIndicator(boolean active);
void showMissingTask();
void hideTitle();
void showTitle(String title);
void hideDescription();
void showDescription(String description);
void showCompletionStatus(boolean complete);
void showEditTask(String taskId);
void showTaskDeleted();
void showTaskMarkedComplete();
void showTaskMarkedActive();
boolean isActive();
}
interface Presenter extends BasePresenter {
void editTask();
void deleteTask();
void completeTask();
void activateTask();
}
}
在activity中分别初始化View和Presenter
TaskDetailActivity.java
protected void onCreate(Bundle savedInstanceState) {
String taskId = getIntent().getStringExtra(EXTRA_TASK_ID);
//初始化View
TaskDetailFragment taskDetailFragment = (TaskDetailFragment) getSupportFragmentManager()
.findFragmentById(R.id.contentFrame);
if (taskDetailFragment == null) {
taskDetailFragment = TaskDetailFragment.newInstance(taskId);
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
taskDetailFragment, R.id.contentFrame);
}
// 初始化 presenter
new TaskDetailPresenter(
taskId,
Injection.provideTasksRepository(getApplicationContext()),
taskDetailFragment);
}
TaskDetailPresenter.java
public class TaskDetailPresenter implements TaskDetailContract.Presenter {
public TaskDetailPresenter(@Nullable String taskId,
@NonNull TasksRepository tasksRepository,
@NonNull TaskDetailContract.View taskDetailView) {
mTaskId = taskId;
//获取数据仓库,也就是Model层的引用
mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
//获取View层的引用
mTaskDetailView = checkNotNull(taskDetailView, "taskDetailView cannot be null!");
//将自己传给View层,这样View就有了presenter的引用
mTaskDetailView.setPresenter(this);
}
/**
*初始化数据
**/
@Override
public void start() {
openTask();
}
private void openTask() {
if (Strings.isNullOrEmpty(mTaskId)) {
mTaskDetailView.showMissingTask();
return;
}
mTaskDetailView.setLoadingIndicator(true);
mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() {
@Override
public void onTaskLoaded(Task task) {
// The view may not be able to handle UI updates anymore
if (!mTaskDetailView.isActive()) {
return;
}
mTaskDetailView.setLoadingIndicator(false);
if (null == task) {
//没有数据显示空页面
mTaskDetailView.showMissingTask();
} else {
//数据加载完成后改变View显示状态
showTask(task);
}
}
@Override
public void onDataNotAvailable() {
// The view may not be able to handle UI updates anymore
if (!mTaskDetailView.isActive()) {
return;
}
mTaskDetailView.showMissingTask();
}
});
}
}
TaskDetailPresenter.java
public class TaskDetailFragment extends Fragment implements TaskDetailContract.View {
//调用presenter的start方法开始加载数据
public void onResume() {
super.onResume();
mPresenter.start();
}
//保存presenter引用
@Override
public void setPresenter(@NonNull TaskDetailContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
}