[]MPC模式
()视图用来呈现模型,视图通常直接从模型中取得它需要显示的状态与数据。
()控制器取得用户的输入并解读其对模型的意思。
()模型持有所有的数据,状态,和程序逻辑。模型没有注意到视图和控制器,虽然它提供了操作和检索状态的接口,并发送状态改变通知观察者。
()模型使用观察者模式,以便观察者更新,同时保持两者之间解耦。
()控制器是视图的策略,视图可以使用不同的控制器实现,得到不同的行为。
()视图使用组合模式实现用户界面。
[]MVP模式
()View:视图层,在View层中只负责对数据的展示,提供友好的界面与用户进行交互。在Android开发中通常将Activity或者Fragment作为View层。
()Model:数据层。不仅仅是数据模型,它还负责对数据的存取操作,例如对数据库的读写,网络的数据的请求等。
()Presenter:它是连接View层与Model层的桥梁并对业务逻辑进行处理。在MVP架构中Model与View无法直接进行交互。所以在Presenter层它会从Model层获得所需要的数据,进行一些适当的处理后交由View层进行显示。这样通过Presenter将View与Model进行隔离,使得View和Model之间不存在耦合,同时也将业务逻辑从View中抽离。
在MVP架构中将这三层分别抽象到各自的接口当中。通过接口将层次之间进行隔离,而Presenter对View和Model的相互依赖也是依赖于各自的接口。这点符合了接口隔离原则,也正是面向接口编程。在Presenter层中包含了一个View接口,并且依赖于Model接口,从而将Model层与View层联系在一起。而对于View层会持有一个Presenter成员变量并且只保留对Presenter接口的调用,具体业务逻辑全部交由Presenter接口实现类中处理。
()分析谷歌官方示例todo‑mvp项目的addedittask包为例来了解MVP(https://github.com/googlesamples/android-architecture/tree/todo-mvp/)
Presenter基类
public interface BasePresenter {
void start();
}
只有start()。该方法是用于Presenter从Model层获取数据并调用View中的方法改变界面显示。该方法一般是在Fragment中的onResume()中调用。
View基类
public interface BaseView<T> {
void setPresenter(T presenter);
}
只有setPresenter(),对于View层会存在一个Presenter对象。该方法是View用来初始化Presenter对象。该方法一般是在Presenter中的构造函数中调用。
契约类:官方的mvp加入了***Contract类来统一管理View与Presenter的所有的接口,使得View与Presenter中有哪些功能很明确,维护简单。
public interface AddEditTaskContract {
interface View extends BaseView<Presenter> {
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();
boolean isDataMissing();
}
}
View层
public class AddEditTaskActivity extends AppCompatActivity {
.......
private AddEditTaskPresenter mAddEditTaskPresenter;
.......
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask_act);
.......
AddEditTaskFragment addEditTaskFragment =
(AddEditTaskFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame);
.......
if (addEditTaskFragment == null) {
addEditTaskFragment = AddEditTaskFragment.newInstance();
}
.......
// Create the presenter
mAddEditTaskPresenter = new AddEditTaskPresenter(
taskId,
Injection.provideTasksRepository(getApplicationContext()),
addEditTaskFragment,
shouldLoadDataFromRepo);
}
@Override
protected void onSaveInstanceState(Bundle outState) {
......
outState.putBoolean(SHOULD_LOAD_DATA_FROM_REPO_KEY, mAddEditTaskPresenter.isDataMissing());
super.onSaveInstanceState(outState);
}
}
()AddEditTaskActivity并没有实现任何接口,只是加载Fragment对象(AddEditTaskFragment addEditTaskFragment),初始化Presenter对象(AddEditTaskPresenter mAddEditTaskPresenter)。在onSaveInstanceState()中调用Presenter对象的isDataMissing()。
()将Fragment对象(addEditTaskFragment)作为Presenter对象的构造函数参数被传入,这样就可以在Presenter对象中调用View对象的方法。
public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View {
......
public static AddEditTaskFragment newInstance() {
return new AddEditTaskFragment();
}
@Override
public void onResume() {
super.onResume();
mPresenter.start();
}
@Override
public void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
......
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.saveTask(mTitle.getText().toString(), mDescription.getText().toString());
}
});
}
......
@Override
public void showEmptyTaskError() {
Snackbar.make(mTitle, getString(R.string.empty_task_message), Snackbar.LENGTH_LONG).show();
}
@Override
public void showTasksList() {
getActivity().setResult(Activity.RESULT_OK);
getActivity().finish();
}
@Override
public void setTitle(String title) {
mTitle.setText(title);
}
@Override
public void setDescription(String description) {
mDescription.setText(description);
}
@Override
public boolean isActive() {
return isAdded();
}
}
()AddEditTaskFragment实现View接口(AddEditTaskContract.View),并持有Presenter对象(AddEditTaskContract.Presenter mPresenter),在显示时(onResume())和FloatingActionButton点击时(onActivityCreated()的点击事件中)分别调用Presenter的start()和saveTask()。
()其中setPresenter(AddEditTaskContract.Presenter presenter),showEmptyTaskError(),showTasksList(),setTitle(String title),setDescription(String description),isActive()是View接口实现方法。
()通过setPresenter()让View对象(AddEditTaskFragment)获得了Presenter实例(mPresenter)。
()官方对于采用Fragment的原因给出了两种解释。
Activity作为全局的控制者将Presenter于View联系在一起,把Fragment作为view,这样两者就能各司其职。
采用Fragment更有利于平板电脑的布局或者是多视图屏幕。
Presenter层
public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
TasksDataSource.GetTaskCallback {
@NonNull
private final TasksDataSource mTasksRepository;
@NonNull
private final AddEditTaskContract.View mAddTaskView;
......
public AddEditTaskPresenter(@Nullable String taskId,@NonNull TasksDataSource tasksRepository,
@NonNull AddEditTaskContract.View addTaskView, boolean shouldLoadDataFromRepo) {
......
mTasksRepository = checkNotNull(tasksRepository);
mAddTaskView = checkNotNull(addTaskView);
......
mAddTaskView.setPresenter(this);
}
@Override
public void start() {
if (!isNewTask() && mIsDataMissing) {
populateTask();
}
}
@Override
public void saveTask(String title, String description) {
if (isNewTask()) {
createTask(title, description);
} else {
updateTask(title, description);
}
}
@Override
public void populateTask() {
if (isNewTask()) {
throw new RuntimeException("populateTask() was called but task is new.");
}
mTasksRepository.getTask(mTaskId, this);
}
@Override
public void onTaskLoaded(Task task) {
if (mAddTaskView.isActive()) {
mAddTaskView.setTitle(task.getTitle());
mAddTaskView.setDescription(task.getDescription());
}
mIsDataMissing = false;
}
@Override
public void onDataNotAvailable() {
if (mAddTaskView.isActive()) {
mAddTaskView.showEmptyTaskError();
}
}
@Override
public boolean isDataMissing() {
return mIsDataMissing;
}
private boolean isNewTask() {
return mTaskId == null;
}
private void createTask(String title, String description) {
Task newTask = new Task(title, description);
if (newTask.isEmpty()) {
mAddTaskView.showEmptyTaskError();
} else {
mTasksRepository.saveTask(newTask);
mAddTaskView.showTasksList();
}
}
private void updateTask(String title, String description) {
if (isNewTask()) {
throw new RuntimeException("updateTask() was called but task is new.");
}
mTasksRepository.saveTask(new Task(title, description, mTaskId));
mAddTaskView.showTasksList();
}
}
()AddEditTaskPresenter实现Presenter接口(AddEditTaskContract.Presenter)和GetTaskCallback接口(TasksDataSource.GetTaskCallback ),其中GetTaskCallback是Model层回调接口。AddEditTaskPresenter持有View层对象(AddEditTaskContract.View mAddTaskView)和Model层对象(TasksDataSource mTasksRepository)。并在构造函数中初始化,同时在构造函数中调用setPresenter()让View对象初始化Presenter对象。
()在Presenter的start()调用Model层对象(TasksDataSource)的getTask(),
()在Presenter的saveTask()中,如果没有新的任务,调用createTask()创建新任务,如果有新的任务,调用updateTask()修改任务。
在createTask()中,如果任务是空的,调用View层对象(AddEditTaskFragment)的showEmptyTaskError(),如果任务不是空的,调用Model层对象(TasksDataSource)的saveTask()和View层对象(AddEditTaskFragment)的showTasksList()。
在updateTask()中,如果没有新的任务,抛出异常,如果有新的任务,调用Model层对象(TasksDataSource)的saveTask()和View层对象(AddEditTaskFragment)的showTasksList()。
()在Presenter的isDataMissing()被调用时。
()onTaskLoaded()和onDataNotAvailable()是实现GetTaskCallback接口的方法,主要是Model层对象(TasksDataSource)操作数据后被调用。
()onTaskLoaded()和onDataNotAvailable()中调用View层对象(AddEditTaskFragment)的一些方法。
Model层
public interface TasksDataSource {
......
interface GetTaskCallback {
void onTaskLoaded(Task task);
void onDataNotAvailable();
}
......
void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);
void saveTask(@NonNull Task task);
......
}
public class TasksLocalDataSource implements TasksDataSource {
......
@Override
public void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) {
Runnable runnable = new Runnable() {
@Override
public void run() {
final Task task = mTasksDao.getTaskById(taskId);
mAppExecutors.mainThread().execute(new Runnable() {
@Override
public void run() {
if (task != null) {
callback.onTaskLoaded(task);
} else {
callback.onDataNotAvailable();
}
}
});
}
};
mAppExecutors.diskIO().execute(runnable);
}
@Override
public void saveTask(@NonNull final Task task) {
checkNotNull(task);
Runnable saveRunnable = new Runnable() {
@Override
public void run() {
mTasksDao.insertTask(task);
}
};
mAppExecutors.diskIO().execute(saveRunnable);
}
......
}
()saveTask()对数据进行操作。
()getTask()如果数据进行操作成功调用GetTaskCallback接口的onTaskLoaded(),如果数据进行操作失败调用GetTaskCallback接口的onDataNotAvailable()。
()MVP模式的不同实现方式
[] 谷歌提供的MVP模式主要思想(Activity或Fragment为View):
定义一个View层接口,让Activity或Fragment实现View层接口;
定义一个Presenter层接口,让其子类实现Presenter;
在View实现类Activity或Fragment中包含Presenter对象,并在Presenter的构造方法中传入View对象;
主要是将Activity或Fragment看做View,
优点:
()Presenter层逻辑的复用
这样可能会存在的问题:
(1)Activity作为Context总会有一些业务逻辑,比如发送Intent,启动Service和执行FragmentTransisitons等这些逻辑在View层中不合理。因为这些需要依赖Context。
(2)Activity或Fragment作为View不能复用,需要多次的去在每个Activity或Fragment做一些初始化View的操作,每个界面都要写一遍。
[]新思路(Activity或Fragment看做Presenter)
将Activity或Fragmen(还可以是Adapter)作为Presenter层,Presenter层包含一个View层的类(ViewDelegate对象)来间接操作View层对外提供的方法,从而做到完全解耦视View层 。
优点:
(1)可以使用Activity本身的生命周期去处理逻辑,而不需要强加给另一个包含类(Presenter对象),甚至记忆额外自定义的生命周期。
(2)独立的View对象可以很好的传递给Presenter层(Activity或者Fragment),而不需要改任何代码。可以让View层复用。
这样可能会存在的问题:
()视图逻辑不能复用。
新思路的具体实现可以参考文章(数据绑定可以忽略,因为DataBinding本身支持双向绑定):
https://github.com/kymjs/TheMVP
参考以下文章:
Google Android架构蓝图
https://github.com/googlesamples/android-architecture