一、組成
下面一張圖勝過千言萬語
用一句話來概括,就說P將M和V分開了,其實也沒這麼簡單,P會將自己傳遞給V,然後在V中進行一些邏輯
二、分析
如下是Google官方基礎MVP程序的框架
我們發現在主包下面有6個子包和兩個接口
- addedittask:添加修改界面
- data:數據源
- statistics:統計界面
- taskdetail:Todo item 詳情頁見面
- tasks:Todo 事件列表界面(主界面)
- util:幫助工具類
- BasePresenter、BaseView:presenter、view接口基類
我們發現關鍵概念裏面講的4個屬性就是這裏面的4個子包,並且這4個子包有很大的相似性,它們都有下面4個接口或者類
- Contract
- Activity
- Fragment
- Presenter
三、代碼
下面以taskdetail爲例子來進行代碼的分析
(1)TaskDetailContract
這是一個合同類,其中包含了兩個接口,一個是View,一個是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();
}
}
(2)TaskDetailActivity
可以看到在Activity中主要實現了兩大功能,一個是Fragment也就是View的初始化,另一個就是Presenter的初始化,在Presenter的初始化過程中需要傳入兩個參數,一個是View,一個是數據庫操作類,這同時也說明了Presenter對V和M的連通行。
public class TaskDetailActivity extends AppCompatActivity {
public static final String EXTRA_TASK_ID = "TASK_ID";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.taskdetail_act);
// Set up the toolbar.
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);
ab.setDisplayShowHomeEnabled(true);
// Get the requested task id
String taskId = getIntent().getStringExtra(EXTRA_TASK_ID);
TaskDetailFragment taskDetailFragment = (TaskDetailFragment) getSupportFragmentManager()
.findFragmentById(R.id.contentFrame);
if (taskDetailFragment == null) {
taskDetailFragment = TaskDetailFragment.newInstance(taskId);
ActivityUtils.addFragmentToActivity(getSupportFragmentManager(),
taskDetailFragment, R.id.contentFrame);
}
// Create the presenter
new TaskDetailPresenter(
taskId,
Injection.provideTasksRepository(getApplicationContext()),
taskDetailFragment);
}
@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
(3)TaskDetailPersenter
終於到了Persenter了,這個傢伙的邏輯應該是很複雜吧,畢竟要實現M和V的橋樑作用,但是這裏只是實現來一些方法,這些方法是用來操作數據庫和View的,其中數據庫和View的具體實現方法還是由其自己來實現。
因此這裏的邏輯並不複雜,最關鍵的一個地方就是通過mTaskDetailView.setPresenter(this)方法將自己傳遞到View中
這裏的mTaskDetailView是通過參數傳遞進來的,代碼太多了,所以精簡一下
public class TaskDetailPresenter implements TaskDetailContract.Presenter {
public TaskDetailPresenter(@Nullable String taskId,
@NonNull TasksRepository tasksRepository,
@NonNull TaskDetailContract.View taskDetailView) {
mTaskId = taskId;
mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
mTaskDetailView = checkNotNull(taskDetailView, "taskDetailView cannot be null!");
mTaskDetailView.setPresenter(this);
}
@Override
public void start() {
openTask();
}
private void openTask() {
}
@Override
public void editTask() {
if (Strings.isNullOrEmpty(mTaskId)) {
mTaskDetailView.showMissingTask();
return;
}
mTaskDetailView.showEditTask(mTaskId);
}
@Override
public void deleteTask() {
if (Strings.isNullOrEmpty(mTaskId)) {
mTaskDetailView.showMissingTask();
return;
}
mTasksRepository.deleteTask(mTaskId);
mTaskDetailView.showTaskDeleted();
}
@Override
public void completeTask() {
}
@Override
public void activateTask() {
}
private void showTask(@NonNull Task task) {
}
}
(4)TaskDetailFragment
我們在Fragment中獲得了Presenter的對象,這樣可以就可以調用Presenter的方法,然後通過Persenter來調用M和V的方法,這樣就可以實現用P來控制M和V了。
以下是部分程序:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.taskdetail_frag, container, false);
setHasOptionsMenu(true);
mDetailTitle = (TextView) root.findViewById(R.id.task_detail_title);
mDetailDescription = (TextView) root.findViewById(R.id.task_detail_description);
mDetailCompleteStatus = (CheckBox) root.findViewById(R.id.task_detail_complete);
// Set up floating action button
FloatingActionButton fab =
(FloatingActionButton) getActivity().findViewById(R.id.fab_edit_task);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.editTask();
}
});
return root;
}
@Override
public void setPresenter(@NonNull TaskDetailContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
尊重作者,尊重原創,參考文章
http://www.jianshu.com/p/569ab68da482
http://www.jianshu.com/p/2ecfc1f4561d