demo地址:https://github.com/googlesamples/android-architecturejava
在這個項目裏,每一個包的分工都很明確,大致上來講,一個包會對應一個界面。一個界面就會對應一個MVP。android
M:仍是模型層和業務層git
V:視圖層。Activity或者Fragment,在這份代碼裏面,Google是把Fragment看成一個V,而不是Activitygithub
P:Prensenter,用來控制V。編程
按個人理解是,MVP主要就是經過P來解耦M和V,P用來溝通M和V,使得二者沒必要直接對話,V能夠安心的負責顯示,與用戶的交互,以及數據的操做工做都交給P來完成。這樣毫無疑問,java文件會變多,可是整個的代碼結構、思路會更加清晰,更容易打理和維護。ide
M:定義了一個接口TasksDataSource.java,從接口能夠看出,主要也就是一些數據的操做,跟之前的MVC區別不大。這個沒啥好說的。函數
public interface TasksDataSource { interface LoadTasksCallback { void onTasksLoaded(List<Task> 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); }
這裏將V和P的接口都放在一個***Contract.java中,這樣便於管理,切一目瞭然。ui
/** * This specifies the contract between the view and the 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(); } }
//BaseView.java public interface BaseView<T> { void setPresenter(T presenter); } //BasePresenter.java public interface BasePresenter { void start(); }
V:前面說到Google將Fragment看做一個V而不是Activity,因此這裏用Fragment來實現V接口。this
public class TasksFragment extends Fragment implements TasksContract.View { public TasksFragment() { // Requires empty public constructor } public static TasksFragment newInstance() { return new TasksFragment(); } @Override public void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); mListAdapter = new TasksAdapter(new ArrayList<Task>(0), mItemListener); } @Override public void onResume() { super.onResume(); mPresenter.start(); } @Override public void setPresenter(@NonNull TasksContract.Presenter presenter) { mPresenter = checkNotNull(presenter); } @Override public void onActivityResult(int requestCode, int resultCode, Intent data) { mPresenter.result(requestCode, resultCode); } @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View root = inflater.inflate(R.layout.tasks_frag, container, false); // Set up tasks view // 也就是一般的findView等一些View的初始化常規操做 ListView listView = (ListView) root.findViewById(R.id.tasks_list); listView.setAdapter(mListAdapter); ………… ………… return root; } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.menu_clear: mPresenter.clearCompletedTasks(); break; case R.id.menu_filter: showFilteringPopUpMenu(); break; case R.id.menu_refresh: mPresenter.loadTasks(true); break; } return true; } @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.tasks_fragment_menu, menu); } /** * Listener for clicks on tasks in the ListView. */ TaskItemListener mItemListener = new TaskItemListener() { @Override public void onTaskClick(Task clickedTask) { mPresenter.openTaskDetails(clickedTask); } @Override public void onCompleteTaskClick(Task completedTask) { mPresenter.completeTask(completedTask); } @Override public void onActivateTaskClick(Task activatedTask) { mPresenter.activateTask(activatedTask); } }; private static class TasksAdapter extends BaseAdapter { //adapter } public interface TaskItemListener { void onTaskClick(Task clickedTask); void onCompleteTaskClick(Task completedTask); void onActivateTaskClick(Task activatedTask); } }
能夠看到,全部的交互操做,像點擊一個task,標記完成task等,V並不處理,而是轉交給P去處理,也就是這樣,便將控制的權利交到了P手中。google
P:那麼P是如何扮演一個溝通者和控制者角色的呢?從代碼中能夠看到,P手握M和V二者的引用,這樣即可以輕鬆的作好他的工做了:操做數據,控制顯示,處理與用戶交互。
public class TaskDetailPresenter implements TaskDetailContract.Presenter { private final TasksRepository mTasksRepository; private final TaskDetailContract.View mTaskDetailView; @Nullable private String mTaskId; public TaskDetailPresenter(@Nullable String taskId, @NonNull TasksRepository tasksRepository, @NonNull TaskDetailContract.View taskDetailView) { this.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() { if (null == mTaskId || mTaskId.isEmpty()) { mTaskDetailView.showMissingTask(); return; } mTaskDetailView.setLoadingIndicator(true); mTasksRepository.getTask(mTaskId, new TasksDataSource.GetTaskCallback() { @Override public void onTaskLoaded(Task task) { // The view may not be able to handle UI updates anymore if (!mTaskDetailView.isActive()) { return; } mTaskDetailView.setLoadingIndicator(false); if (null == task) { mTaskDetailView.showMissingTask(); } else { showTask(task); } } @Override public void onDataNotAvailable() { // The view may not be able to handle UI updates anymore if (!mTaskDetailView.isActive()) { return; } mTaskDetailView.showMissingTask(); } }); } @Override public void editTask() { if (null == mTaskId || mTaskId.isEmpty()) { mTaskDetailView.showMissingTask(); return; } mTaskDetailView.showEditTask(mTaskId); } @Override public void deleteTask() { mTasksRepository.deleteTask(mTaskId); mTaskDetailView.showTaskDeleted(); } @Override public void completeTask() { if (null == mTaskId || mTaskId.isEmpty()) { mTaskDetailView.showMissingTask(); return; } mTasksRepository.completeTask(mTaskId); mTaskDetailView.showTaskMarkedComplete(); } @Override public void activateTask() { if (null == mTaskId || mTaskId.isEmpty()) { mTaskDetailView.showMissingTask(); return; } mTasksRepository.activateTask(mTaskId); mTaskDetailView.showTaskMarkedActive(); } private void showTask(Task task) { String title = task.getTitle(); String description = task.getDescription(); if (title != null && title.isEmpty()) { mTaskDetailView.hideTitle(); } else { mTaskDetailView.showTitle(title); } if (description != null && description.isEmpty()) { mTaskDetailView.hideDescription(); } else { mTaskDetailView.showDescription(description); } mTaskDetailView.showCompletionStatus(task.isCompleted()); } }
我發現像以前那本《Android編程權威指南》還有Google官方這個例子,對Fragment都情有獨鍾,都在鼓勵使用Fragment而不是Activity,因此Fragment理所固然的成爲了V。那麼在MVP中Activity幹嗎呢?
public class TasksActivity extends AppCompatActivity { private static final String CURRENT_FILTERING_KEY = "CURRENT_FILTERING_KEY"; private DrawerLayout mDrawerLayout; private TasksPresenter mTasksPresenter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.tasks_act); // Set up the toolbar. Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar ab = getSupportActionBar(); ab.setHomeAsUpIndicator(R.drawable.ic_menu); ab.setDisplayHomeAsUpEnabled(true); // Set up the navigation drawer. mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerLayout.setStatusBarBackground(R.color.colorPrimaryDark); NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view); if (navigationView != null) { setupDrawerContent(navigationView); } TasksFragment tasksFragment = (TasksFragment) getSupportFragmentManager().findFragmentById(R.id.contentFrame); if (tasksFragment == null) { // Create the fragment tasksFragment = TasksFragment.newInstance(); ActivityUtils.addFragmentToActivity( getSupportFragmentManager(), tasksFragment, R.id.contentFrame); } // Create the presenter mTasksPresenter = new TasksPresenter( Injection.provideTasksRepository(getApplicationContext()), tasksFragment); // Load previously saved state, if available. if (savedInstanceState != null) { TasksFilterType currentFiltering = (TasksFilterType) savedInstanceState.getSerializable(CURRENT_FILTERING_KEY); mTasksPresenter.setFiltering(currentFiltering); } } }
Activity主要用來建立Fragment、初始化P(也就是關聯V和P)
在BaseView中有個setPresenter()方法,而一般在P的構造函數中獲得V的實例後會調用該方法來實現V和P的綁定。
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); }
在V經過setPresenter獲得P後,便在onResume()中調用BasePresenter的start()方法來初始化P,其實也就是初始化UI界面,畢竟P掌管了V的控制權。
@Override public void onResume() { super.onResume(); mPresenter.start(); }