一、 MVC和MVP
1. MVC
MVC的全稱為Model-View-Controller,即模型-視圖-控制器。
- Model:處理數(shù)據(jù)和業(yè)務(wù)邏輯等
- View:顯示界面,展示結(jié)果等
- Controller:控制流程,處理交互
MVC各個(gè)模塊通信方式如下:

2. MVP
MVP的全稱為Model-View-Presenter,即模型-視圖-協(xié)調(diào)器(主持者)
- Model:處理數(shù)據(jù)和業(yè)務(wù)邏輯等
- View:顯示界面,展示結(jié)果等
- Presenter:協(xié)調(diào)Model和View模塊工作,處理交互
MVP各個(gè)模塊通信方式如下:

3. MVC和MVP區(qū)別
在MVC模式中,View和Model可以直接交互;在MVP模式中,View和Model模塊不能直接交互,View通過(guò)Presenter與Model間接交互。
在MVC中,Controller是基于行為的,可以被多個(gè)View共享,可以負(fù)責(zé)決定顯示哪個(gè)View;在MVP中View和Presenter是一對(duì)一或這一對(duì)多的,并且Presenter和View是通過(guò)接口交互的。
二、 Google官方MVP示例
1. 項(xiàng)目說(shuō)明
項(xiàng)目地址:https://github.com/googlesamples/android-architecture
項(xiàng)目?jī)?nèi)容說(shuō)明:
已完成的示例
- todo-mvp/ - mvp基礎(chǔ)架構(gòu)示例
- todo-mvp-loaders/ - 基于todo-mvp,獲取數(shù)據(jù)部分使用了Loaders
- todo-mvp-databinding/ - 基于todo-mvp,使用了Data Binding Library
進(jìn)行中的示例
- dev-todo-mvp-contentproviders/ - 基于todo-mvp-loaders,使用了Content Providers
- dev-todo-mvp-clean/ - 基于todo-mvp,使用了Clean Architecture的概念.
- dev-todo-mvp-dagger/ - 基于todo-mvp,使用了Dagger2進(jìn)行依賴注入
2. todo-mvp基礎(chǔ)架構(gòu)項(xiàng)目分析
2.1 代碼組織方式
項(xiàng)目的app/src/main/java目錄中代碼的組織方式是按照功能模塊組織的,每個(gè)功能為一個(gè)包,每個(gè)功能模塊的內(nèi)部分為xActivity、xFragment、xPresenter、xContract四個(gè)類文件,其作用如下:
- xActivity主要負(fù)責(zé)創(chuàng)建View和Presenter實(shí)例,并將它們聯(lián)系起來(lái)
- xFragment實(shí)現(xiàn)View接口,作為MVP結(jié)構(gòu)中的View
- xPresenter實(shí)現(xiàn)Presenter接口,是MVP結(jié)構(gòu)中的Presenter
- xContract作為合同接口,統(tǒng)一管理View和Presenter的接口,便于查看和維護(hù)View和Presenter的功能
Model作為單獨(dú)的模塊存放與data目錄下
項(xiàng)目的app/src/main/java目錄中結(jié)構(gòu)如下:

2.2 MVP實(shí)現(xiàn)方式
以添加或編輯任務(wù)功能模塊(addedittask)為例
2.2.1 View和Present基礎(chǔ)接口
- BaseView接口中有setPresenter方法,用于將Presenter實(shí)例傳入View中,在Presenter的實(shí)現(xiàn)類的構(gòu)造方法中調(diào)用。
public interface BaseView<T> {
void setPresenter(T presenter);
}
- BasePresenter接口中有start方法,用于Presenter開(kāi)始獲取數(shù)據(jù)并調(diào)用View進(jìn)行界面顯示,在View的實(shí)現(xiàn)類Fragment中的onResume方法中調(diào)用。
public interface BasePresenter {
void start();
}
2.2.2 AddEditTaskContract
AddEditTaskContract是一個(gè)合同接口,其中包含了View和Presenter接口,便于查看和維護(hù)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 createTask(String title, String description);
void updateTask( String title, String description);
void populateTask();
}
}
2.2.3 AddEditTaskActivity
AddEditTaskActivity中創(chuàng)建了View的實(shí)現(xiàn)類AddEditTaskFragment的實(shí)例和Presenter的實(shí)現(xiàn)類AddEditTaskPresenter的實(shí)例,并把它們聯(lián)系起來(lái)。
public class AddEditTaskActivity extends AppCompatActivity {
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.addtask_act);
...
// 創(chuàng)建AddEditTaskFragment實(shí)例
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);
}
// 創(chuàng)建Presenter實(shí)例,傳入Model實(shí)例和AddEditTaskFragment實(shí)例,建立View和Presenter之間的聯(lián)系
new AddEditTaskPresenter(
taskId,
Injection.provideTasksRepository(getApplicationContext()),
addEditTaskFragment);
}
...
}
2.2.4 AddEditTaskFragment
AddEditTaskFragment實(shí)現(xiàn)了AddEditTaskContract接口中的View接口,其中有一個(gè)Presenter實(shí)例,在onResume方法中調(diào)用Presenter的start方法。
public class AddEditTaskFragment extends Fragment implements AddEditTaskContract.View {
private AddEditTaskContract.Presenter mPresenter;
public static AddEditTaskFragment newInstance() {
return new AddEditTaskFragment();
}
public AddEditTaskFragment() {
// Required empty public constructor
}
@Override
public void onResume() {
super.onResume();
// 調(diào)用start方法
mPresenter.start();
}
// 重寫(xiě)setPresenter方法
@Override
public void setPresenter(@NonNull AddEditTaskContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
...
}
2.2.5 AddEditTaskPresenter
AddEditTaskPresenter實(shí)現(xiàn)了AddEditTaskContract接口中的Presenter接口,其中有一個(gè)View實(shí)例,在構(gòu)造方法中調(diào)用View的setPresenter方法與View建立聯(lián)系。
public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
TasksDataSource.GetTaskCallback {
// Model實(shí)例,完成數(shù)據(jù)獲取
@NonNull
private final TasksDataSource mTasksRepository;
@NonNull
private final AddEditTaskContract.View mAddTaskView;
@Nullable
private String mTaskId;
public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource tasksRepository,
@NonNull AddEditTaskContract.View addTaskView) {
mTaskId = taskId;
mTasksRepository = checkNotNull(tasksRepository);
mAddTaskView = checkNotNull(addTaskView);
mAddTaskView.setPresenter(this);
}
// 重寫(xiě)start方法,開(kāi)始獲取數(shù)據(jù)
@Override
public void start() {
if (mTaskId != null) {
populateTask();
}
}
...
}
3. 總結(jié)
官方的實(shí)例項(xiàng)目有十分清晰的模塊劃分,復(fù)雜度也相對(duì)較低,易于學(xué)習(xí),相對(duì)于普通的MVP增加了合同接口,便于模塊功能的管理和擴(kuò)展。