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 ...
随机推荐
- MyEclipse8.5优化经验
第一步: 取消自动validation validation有一堆,什么xml.jsp.jsf.js等等,我们没有必要全部都去自动校验一下,只是需要的时候才会手工校验一下! 取消方法: ...
- DataBinding注意事项Error parsing XML: duplicate attribute以及如何在listview中使用DataBinding
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...
- JavaBean-- 保存 范围
1. page:当前页 2. request:一次服务器跳转范围中 3. session:一次用户操作范围,重新打开浏览器失效 4. application:整个服务器保存,服务器关闭才失效 定义一个 ...
- 关于tomcat 成功运行之后内存泄露
在window-preferences 里 搜索 tomcat-jdk 加上以下内容即可 -Xms256m -Xmx512m -XX:MaxNewSize=256m -XX:MaxPermSize= ...
- Beautiful Subarrays
Beautiful Subarrays time limit per test 3 seconds memory limit per test 512 megabytes input standard ...
- UIButton 解析
IOS之按钮控件--Button全解析及使用 转载自:forget IOS开发中伴随我们始终的 最常用的几个空间之一 -- UIButton 按钮,对于button今天在此做一些浅析,并介绍下主流用 ...
- Android EditText的设置(转)
1.输入法Enter键图标的设置: 软件盘的界面替换只有一个属性android:imeOptions,这个属性的可以取的值有normal,actionUnspecified,actionNone,ac ...
- expected: file:///
[java] java.lang.IllegalArgumentException: Wrong FS: hdfs://192.168.190.128:9000/user/hadoop/output/ ...
- SIFT
简介 SIFT(scale invariant feature transform)——尺度不变特征转换,用来检测和描述局部特征,运用范围包括object recognition(目标检测), rob ...
- web容器启动顺序
web容器启动顺序: 第一:context-param 第二:Listerer 第三:Filter 第四:servlet