demo地址:https://github.com/googlesamples/android-architecture

在这个项目里,每个包的分工都很明确,大体上来说,一个包会对应一个界面。一个界面就会对应一个MVP。

M:还是模型层和业务层

V:视图层。Activity或者Fragment,在这份代码里面,Google是把Fragment当作一个V,而不是Activity

P:Prensenter,用来控制V。

按我的理解是,MVP主要就是通过P来解耦M和V,P用来沟通M和V,使得两者不必直接对话,V可以安心的负责显示,与用户的交互,以及数据的操作工作都交给P来完成。这样毫无疑问,java文件会变多,但是整个的代码结构、思路会更加清晰,更容易打理和维护。

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中,这样便于管理,切一目了然。

/**
* 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接口。

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手中。

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();
}

MVP学习笔记——参考Google官方demo的更多相关文章

  1. Andriod学习笔记 - 参考

    Andriod学习笔记 - 参考 自定义实现圆形播放进度条(android,飞一般的感觉) 盘点Android开发者必备的十大开发工具

  2. [原创]java WEB学习笔记30:Cookie Demo 之显示最近浏览的记录

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  3. [原创]java WEB学习笔记29:Cookie Demo 之自动登录

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  4. ICE学习笔记一----运行官方的java版demo程序

    建议新手和我一样,从官网下载英文文档,开个有道词典,慢慢啃. 官方文档下载: http://download.csdn.net/detail/xiong_mao_1/6300631 程序代码就不说了, ...

  5. Guava学习笔记:Google Guava 类库简介

    http://www.cnblogs.com/peida/tag/Guava/ Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, cachin ...

  6. maven profiles、filters、resources学习笔记 及 常用 plugin demo

    这里只记了学习以下博客后,自己做的一个总结. 来源:http://blog.csdn.net/fengchao2016/article/details/72726101 profiles定义了一些不同 ...

  7. Git 学习笔记参考

    1.参考学习资料 网上资料: http://www.cnblogs.com/aoguren/p/4189086.html http://www.liaoxuefeng.com/wiki/0013739 ...

  8. DuiLib学习笔记1——编译运行demo

    c++中皮肤问题比较麻烦,MFC自带的太难用.DirectUI界面库就比较强大了,之前像skin++之类的基于DirectUI收费昂贵.DuiLib是基于DirectUI的界面库,可以将用户界面和处理 ...

  9. docker学习笔记 参考

    https://www.cnblogs.com/YDDMAX/p/6045079.html 参考此人播客:docker 分类 http://www.cnblogs.com/51kata/categor ...

随机推荐

  1. html5 localStorage和sessionStorage

    该随便来自: http://www.cnblogs.com/yuzhongwusan/archive/2011/12/19/2293347.html html5中的Web Storage包括了两种存储 ...

  2. HDU - 1205 I NEED A OFFER!

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1203 题意: 该题要求得到一份offer的最大概率,在例子中的0.44 = 1-(1-0.2)*(1- ...

  3. JSch - Java实现的SFTP

    JSch - Java实现的SFTP(文件上传详解篇)     JSch是Java Secure Channel的缩写.JSch是一个SSH2的纯Java实现.它允许你连接到一个SSH服务器,并且可以 ...

  4. HTML元素分类:块级元素 内联元素和内联块状元素

    在CSS中,html中的标签元素大体被分为三种不同的类型:块状元素.内联元素(又叫行内元素)和内联块状元素. 1,块状元素 常用的块状元素有: <div>.<p>.<h1 ...

  5. SVM阅读资料

    1,Andrew Ng机器学习公开课笔记 -- 支持向量机 2,http://blog.pluskid.org/?page_id=683 3,支持向量机SVM(一) 4,机器学习中的算法(2)-支持向 ...

  6. Struts2 语法--result type

    result type: dispatcher,redirect:只能跳转到jsp,html之类的页面,dispatcher属于服务器跳转, redirect属于客户端跳转 chain: 等同于for ...

  7. CF 672 div2 D

    http://codeforces.com/contest/672/problem/D 题目大意: 有n个人,每个人有pi的钱,然后可以由如下操作,每次都可以挑选一个最富有的人,把它的钱给最穷的人.但 ...

  8. access restriction

    一.既然存在访问规则,那么修改访问规则即可.打开项目的Build Path Configuration页面,打开报错的JAR包,选中Access rules条目,选择右侧的编辑按钮,添加一个访问规则即 ...

  9. Allocation Failure

    up vote 8 down vote accepted "Allocation Failure" is a cause of GC cycle to kick. "Al ...

  10. plsql找外键约束关联的表的方法

    直接Ctrl + 鼠标左键 表名 就可以找到参照表(关联表)的名称 下面的是复杂的方法 这个就是关联的表 这里右键查看 可以查看到参照的表