在Android应用开发中采用MVC好还是MVP好的话题,一直都争议不断,现在Android官方也来凑热闹了,官方出了个开源项目,来描绘一幅架构蓝图,该项目主要包括mvp,mvvm,clean架构,其中不乏Dagger2,rxjava等主流框架,项目中使用不同的架构来实现同一个Todo App,项目地址:https://github.com/googlesamples/android-architecture
今天先来看看MVP在Todo项目中的使用,项目地址:https://github.com/googlesamples/android-architecture/tree/todo-mvp
clone工程,编译运行效果:
App功能分析:
TO-DO就是一个任务清单,首页是展示任务的清单列表,有增加任务,标记任务完成,统计等功能
打开代码目标结构:
分析包,目测
- addedittask是增加和编辑功能
- statistics是任务统计,
- taskdetail是任务详情
- tasks是任务列表
- util是一些工具类
- BasePresenter和BaseView是V和P的基类
- data包是整个M层
分析V层和P层
我们先看BaseView.java1
2
3
4
5public interface BaseView<T> {
void setPresenter(T presenter);
}
BaseView是一个接口,里边只定义一个方法setPresenter,presenter是泛型T
再看BasePresenter.java
1 | public interface BasePresenter { |
BasePresenter也是一个接口,定义了start方法
我们打开tasks包下的TasksContract类,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60public 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();
}
}
TasksContract本身是个接口,里边定义了两个接口View和Presenter,View继承自BaseView,里边定义的是具体操作UI的方法,Presenter继承自BasePresenter,里边主要是一些操作数据的方法
跟踪接口TasksContract.View的实现类TasksFragment1
2
3
4
5
6
7
8
9
10
11
12public class TasksFragment extends Fragment implements TasksContract.View {
private TasksContract.Presenter mPresenter;
@Override
public void setPresenter(@NonNull TasksContract.Presenter presenter) {
mPresenter = checkNotNull(presenter);
}
//省略代码
}
TasksFragment持有TasksContract.Presenter实例,在setPresenter方法将Presenter注入。
谁来调用TasksFragment的setPresenter方法,并没有发现,这个问题先放一下,先看看TasksContract.Presenter实现类TasksPresenter
1 | public class TasksPresenter implements TasksContract.Presenter { |
TasksPresenter类持有TasksRepository和TasksContract.View实例,在构造方法注入,构造方法最后一句执行mTasksView.setPresenter(this);
这样就明白了刚才的问题,TasksFragment的setPresenter方法是在TasksRepository构造中注入,OK,那么TasksPresenter对象由谁创建呢?ctrl+g定位到TasksActivity,在onCreate方法中构造了TastsPresenter
1 | public class TasksActivity extends AppCompatActivity { |
这样看来,TasksActivity在负责创建TasksFragment和TasksPresenter同时,还负责保存TasksPresenter状态
简单分析M层
M层对应刚才分析的data包,目录结构图如下
类分析
- Task 实体类
- TasksDataSource DataSource顶层接口,定义了一些操作数据的抽象方法和回调接口
- TasksRemoteDataSource 实现了TasksDataSource,进行网络操作的DataSource
- TasksLocalDataSource 实现了TasksDataSource,进行本地数据操作的DataSource
- TasksRepository 实现了TasksDataSource,我的理解是M层向上曾提供交付层,持有两种类型的DataSource,根据需求取不同的数据源数据
TasksRepository类分析
1 | public class TasksRepository implements TasksDataSource { |
TasksRepository是一个单例,构造函数注入 tasksRemoteDataSource和tasksLocalDataSource,分析getTasks方法,是获取任务列表的方法,
该方法获取数据源的优先级是内存->本地->网络,如果内存缓存存在且没有过期,取内存,否则,如果过期,取网络,否则,取本地,如果本地数据不可用再取网络,
从本地获取之后,要覆盖内存缓存,从网络获取之后,要同时覆盖本地和网络。
最后,附上官方架构图
总结:此次分析只是浅尝辄止,具体分析期待下次博客
- Activity作为Fragment的承载,创建具体的V和P,同时还用来保存P的状态
- Fragment作为V层来View显示,控制P层数据获取时机
- 具体的Presenter作为P层,与Repository进行数据交互,对V层提供数据显示
- 具体的Repository作为M层的门面供P层调用