已经使用了一段时间的MVP模式,今天再以google官方的安卓架构示例todo-mvp为例,再次学习MVP模式。数据库
在学习todo-mvp以前,先了解一下MVP的优点。bash
其中tasks, taskdetail, addedittask, statistics是四个业务模块。网络
data是数据模块,其中具体的类TasksRepository
担任Model层,负责远程和本地数据的获取。架构
BasePresenter
和BaseView
是presenter 和 view 的基类,在具体模块承担实际功能。最后,util是工具类集合。app
在todoapp中,MVP的具体结构以下图所示: 异步
基类ide
public interface BasePresenter {
void start();
}
复制代码
其中start()
方法的做用是presenter开始获取数据并调用view中方法改变界面显示,其调用时机是在Fragment类的onResume
方法中。函数
public interface BaseView<T> {
void setPresenter(T presenter);
}
复制代码
其中setPresenter()
方法做用是在将presenter实例传入view中,其调用时机是presenter实现类的构造函数中。工具
契约类单元测试
与以前使用的MVP实现不一样,官方的实现中加入了契约类来统一管理view与presenter的全部的接口,这种方式使得view与presenter中有哪些功能,一目了然,维护起来也方便,同时使得view与presenter一一对应,并有效地减小类的数目。
public interface TasksContract {
interface View extends BaseView<Presenter> {
void setLoadingIndicator(boolean active);
void showTasks(List<Task> tasks);
void showAddTask();
void showTaskDetailsUi(String taskId);
void showTaskMarkedComplete();
void showTaskMarkedActive();
void showCompletedTasksCleared();
void showLoadingTasksError();
void showNoTasks();
void showActiveFilterLabel();
void showCompletedFilterLabel();
void showAllFilterLabel();
void showNoActiveTasks();
void showNoCompletedTasks();
void showSuccessfullySavedMessage();
boolean isActive();
void showFilteringPopUpMenu();
}
interface Presenter extends BasePresenter {
void result(int requestCode, int resultCode);
void loadTasks(boolean forceUpdate);
void addNewTask();
void openTaskDetails(@NonNull Task requestedTask);
void completeTask(@NonNull Task completedTask);
void activateTask(@NonNull Task activeTask);
void clearCompletedTasks();
void setFiltering(TasksFilterType requestType);
TasksFilterType getFiltering();
}
}
复制代码
TasksActivity
Activity 在项目中是一个全局的控制者,负责建立 view 以及 presenter 实例,并将两者联系起来。
TasksFragment tasksFragment =
(TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
if (tasksFragment == null) {
// 建立 fragment
tasksFragment = TasksFragment.newInstance();
ActivityUtils.addFragmentToActivity(
getSupportFragmentManager(), tasksFragment, R.id.contentFrame);
}
// 建立 presenter,TasksPresenter是TasksContract.Presenter 的实现类
// 传入两个参数
//1.TasksRepository实例,负责数据层
//2.tasksFragment,是TasksContract.View的实现类,即view实例
mTasksPresenter = new TasksPresenter(
Injection.provideTasksRepository(getApplicationContext()), tasksFragment);
复制代码
其中,经过实例化TasksPresenter
时,传入tasksFragment
,使得在TasksPresenter
中拥有view实例。同时,在实例化时初始化构造函数,调用了setPresenter()
方法,使得view实例中拥有了presenter实例对象,使得二者联系起来。
TasksPresenter
构造函数以下所示:
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);
}
复制代码
TasksFragment
将Fragment做为view层的实现类,使得Activity做为一个全局控制类来建立对象,而Fragment做为view,二者各司其职。同时,Fragment比较灵活,可以方便的处理界面适配的问题。
public class TasksFragment extends Fragment implements TasksContract.View {
...........
public static TasksFragment newInstance() {
return new TasksFragment();
}
...........
@Override
public void onResume() {
super.onResume();
mPresenter.start();
}
...........
@Override
public void setPresenter(@NonNull TasksContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
...........
@Override
public boolean isActive() {
return isAdded();
}
...........
}
复制代码
对于 view 的实现TasksFragment,只挑一部分重要的方法来看。
newInstance ()
方法,实例化TasksFragment对象。setPresenter()
方法继承于父类,经过该方法,view 得到了 presenter 得实例,从而能够调用 presenter 代码来处理业务逻辑。onResume()
中,调用了 presenter 得start()
方法,获取数据并操做view界面的显示。isActive()
方法,经过isAdded()
判断对应Activity是否销毁。在Fragment在执行异步耗时操做后,若是调用Activity实例,应当先使用isActive()
方法加以判断。经过对todo-mvp分析,再次了解学习了MVP。从google提供的例子中能够看出,MVP的实现较为简单,model、view和presenter各个职责明确,便于扩展维护。contract契约类的出现,使得model和presenter结构更加清晰明了。Activity和Fragment的配合,使得Activity职能更为简化,同时View的实现更加灵活。