MVP学习笔记——参考Google官方demo
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的更多相关文章
- Andriod学习笔记 - 参考
Andriod学习笔记 - 参考 自定义实现圆形播放进度条(android,飞一般的感觉) 盘点Android开发者必备的十大开发工具
- [原创]java WEB学习笔记30:Cookie Demo 之显示最近浏览的记录
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- [原创]java WEB学习笔记29:Cookie Demo 之自动登录
本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...
- ICE学习笔记一----运行官方的java版demo程序
建议新手和我一样,从官网下载英文文档,开个有道词典,慢慢啃. 官方文档下载: http://download.csdn.net/detail/xiong_mao_1/6300631 程序代码就不说了, ...
- Guava学习笔记:Google Guava 类库简介
http://www.cnblogs.com/peida/tag/Guava/ Guava 是一个 Google 的基于java1.6的类库集合的扩展项目,包括 collections, cachin ...
- maven profiles、filters、resources学习笔记 及 常用 plugin demo
这里只记了学习以下博客后,自己做的一个总结. 来源:http://blog.csdn.net/fengchao2016/article/details/72726101 profiles定义了一些不同 ...
- Git 学习笔记参考
1.参考学习资料 网上资料: http://www.cnblogs.com/aoguren/p/4189086.html http://www.liaoxuefeng.com/wiki/0013739 ...
- DuiLib学习笔记1——编译运行demo
c++中皮肤问题比较麻烦,MFC自带的太难用.DirectUI界面库就比较强大了,之前像skin++之类的基于DirectUI收费昂贵.DuiLib是基于DirectUI的界面库,可以将用户界面和处理 ...
- docker学习笔记 参考
https://www.cnblogs.com/YDDMAX/p/6045079.html 参考此人播客:docker 分类 http://www.cnblogs.com/51kata/categor ...
随机推荐
- HTML一些小细节
这里主要是记录一些看起来不重要,但是其实作用不小或者使用起来某种情况下好用的东西,又或者是重要的但容易忽略的基础知识 1. HTML5之后的第一个标签是<!DOCTYPE html> 这个 ...
- POJ 1236 Network of Schools (tarjan算法+缩点)
思路:使用tarjan求强连通分量并进行缩点,判断所有入度为0的点,这个点就是必须要给予文件的点,分别计算出度,入度为零的点的个数,取二者的最大值就是把这个图变成强连通需要加的边数. 一个取值需要讨论 ...
- redis 工具类 单个redis、JedisPool 及多个redis、shardedJedisPool与spring的集成配置
http://www.cnblogs.com/edisonfeng/p/3571870.html http://javacrazyer.iteye.com/blog/1840161 http://ww ...
- hibernate不能自动生成表的原因总结
1. upate->create <property name="hbm2ddl.auto">create</property> 2. 2.Mappi ...
- generic type
http://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html
- Material Design设计的开源代码
https://github.com/telly/FloatingAction http://www.csdn.net/article/2014-11-21/2822753-material-desi ...
- 深入浅出Ajax(一)
客户端: <script type="text/javascript"> window.onload = initPage; function initPage() { ...
- Apache下的FileUtils.listFiles方法简单使用技巧
一.引言 Apache提供的很多工具方法非常好用,推荐. 今天在使用的过程中使用到了org.apache.commons.io.FileUtils.listFiles方法,本文主要谈谈这个工具方法的用 ...
- A. Round House
A. Round House time limit per test 1 second memory limit per test 256 megabytes input standard input ...
- pcap filter
今天用tshark抓包,本以为wireshark能用的filter,如“mysql”它也应该能用,其实不然:tshark -f只认识pcap filter,用-R的话,说要用-2,加上-2的话又说什么 ...