一 官方文档说明
概要
这个例子是很多实例变化的基础(后续还有一些实例 ),是mvp模式的简单实现,它采用依赖注入的方式为用户提供本地和远程数据源的存储库,用回调的方式进行异步任务的处理。
mvp 概要图片
注意:在mvp结构中,view 被重载
- android.view.VIew 类将会被当作 “android view”
- view 接收来自解析器(presenter)的指令,被简称为 “view”
Fragments
使用 fragments的两个原因
- 把Activity和fragment 分离 是非常适合实现mvp的,Activity 完全控制和连接view 和 presenters.
- 使用fragment 有利于平板或者多分辨率
概念
四个功能
- Tasks
- TaskDetails
- AddEditTask
- Statistics
每个功能都有
在view 和presenter之间都定义好了协议
Activity负责创建fragment和presenters
fragment 实现view 的接口
-
presenter 实现 presenter接口
一般来说,业务逻辑执行在presenter中,view 用来执行android 的ui工作
view 大多数情况没有业务逻辑,它主要将presenter的命令转为ui操作,并监听用户的操作传递给presenter.
规范接口 用于定义连接 view和presenters。
程序运行
如图所示 先就增加一个任务的操作进行代码分享
代码分析
AddEditTaskActiviy (增加任务的activity)
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask_act); 、
// Set up the toolbar. 设置标题
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
actionBar.setDisplayHomeAsUpEnabled(true);
actionBar.setDisplayShowHomeEnabled(true);
// 1.创建fragment
AddEditTaskFragment addEditTaskFragment = (AddEditTaskFragment)
getSupportFragmentManager().findFragmentById(R.id.contentFrame);
String taskId = null;
if (addEditTaskFragment == null) {
addEditTaskFragment = AddEditTaskFragment.newInstance();
if (getIntent().hasExtra(AddEditTaskFragment.ARGUMENT_EDIT_TASK_ID)) {
taskId = getIntent().getStringExtra(AddEditTaskFragment.ARGUMENT_EDIT_TASK_ID);
actionBar.setTitle(R.string.edit_task);
Bundle bundle = new Bundle();
bundle.putString(AddEditTaskFragment.ARGUMENT_EDIT_TASK_ID, taskId);
addEditTaskFragment.setArguments(bundle);
} else { actionBar.setTitle(R.string.add_task); }
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
addEditTaskFragment, R.id.contentFrame); }
// Create the presenter 2.创建 presenter
new AddEditTaskPresenter( taskId, Injection.provideTasksRepository(getApplicationContext()),
addEditTaskFragment);}
结合文档和代码,再activity的oncreate方法中,主要两个操作
- 创建fragment
- 实例化 presenter
AddEditTaskFragment (View) 代码
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
FloatingActionButton fab = (FloatingActionButton) getActivity().findViewById(R.id.fab_edit_task_done);
fab.setImageResource(R.drawable.ic_done);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.saveTask(mTitle.getText().toString(), mDescription.getText().toString());
}
});
}
在 onActivityCreate中 实现了完成增加任务的按钮,把用户的操作传递给presenter
AddEditTaskFragment 实现了AddEditTaskContract.view接口
AddEditTaskContract 代码
public interface AddEditTaskContract {
interface View extends BaseView {
void showEmptyTaskError();
void showTasksList();
void setTitle(String title);
void setDescription(String description);
boolean isActive();
}
interface Presenter extends BasePresenter {
void saveTask(String title, String description);
void populateTask();
}
}
这个就是文档中说的 contract 协议 定义了view 的接口,供view去实现里面的方法,定义了presenter接口供对应的presenter去实现。
BaseView 基view 因为所有的view都要关联一个presenter
public interface BaseView {
void setPresenter(T presenter);
}
看完View层 ,再看P层
AddEditTaskPresenter (P 层代码)
实现了 AddEditTaskContract.Presenter接口
构造方法
//三个参数 任务 id,数据源,关联的view
public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource
tasksRepository,
@NonNull AddEditTaskContract.View addTaskView) {
mTaskId = taskId;
mTasksRepository = checkNotNull(tasksRepository);
mAddTaskView = checkNotNull(addTaskView);
//view 设置 presenter
mAddTaskView.setPresenter(this);
}
接下来看AddEditTaskFragment 中完成按钮的点击事件
mPresenter.saveTask(mTitle.getText().toString(), mDescription.getText().toString());
也就是present的saveTask方法
@Override
public void saveTask(String title, String description) {
if (isNewTask()) {
createTask(title, description);
} else {
updateTask(title, description);
}}
直接看 createTask方法
private void createTask(String title, String description) {
//新建一个任务
Task newTask = new Task(title, description);
if (newTask.isEmpty()) {
mAddTaskView.showEmptyTaskError();
} else {
//保存数据
mTasksRepository.saveTask(newTask);
//通知view 层展示新的数据 (前面文档:view层通过接收present的指令)
mAddTaskView.showTasksList();
}}
AddEditTaskPresenter 还实现了 TasksDataSource.GetTaskCallback
TasksDataSource(M 层)
数据层的两个方法
@Override
public void onTaskLoaded(Task task) {
// The view may not be able to handle UI updates anymore
if (mAddTaskView.isActive()) {
mAddTaskView.setTitle(task.getTitle());
mAddTaskView.setDescription(task.getDescription());
}}
@Override
public void onDataNotAvailable() {
// The view may not be able to handle UI updates anymore
if (mAddTaskView.isActive()) {
mAddTaskView.showEmptyTaskError();
}}
获取数据的接口
/**
* Main entry point for accessing tasks data.
* * For simplicity, only getTasks() and getTask() have callbacks. Consider adding callbacks to other
* methods to inform the user of network/database errors or successful operations.
* For example, when a new task is created, it's synchronously stored in cache but usually every
* operation on database or network should be executed in a different thread.
*/
public interface TasksDataSource {
interface LoadTasksCallback {
void onTasksLoaded(List tasks);
void onDataNotAvailable();
} interface GetTaskCallback {
void onTaskLoaded(Task task);
void onDataNotAvailable();
}
void getTasks(@NonNull LoadTasksCallback callback);
void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);
void saveTask(@NonNull Task task);
void completeTask(@NonNull Task task);
void completeTask(@NonNull String taskId);
void activateTask(@NonNull Task task);
void activateTask(@NonNull String taskId);
void clearCompletedTasks();
void refreshTasks();
void deleteAllTasks();
void deleteTask(@NonNull String taskId);}
MVP的好处
- 分离了视图和业务逻辑,降低耦合
- 简化了Activity 的代码