Google TODO-MVP-Loaders 简要分析
来源:互联网 发布:大学生旅游数据统计 编辑:程序博客网 时间:2024/05/17 09:29
Google TODO-MVP-Loaders 简要分析
之前写的项目都是采用 MVC 模式(Model - View - Controller),虽然极力避免V层中出现逻辑处理,可整体还是凌乱一些。之前也看 鸿洋大神 的 浅谈 MVP in Android的文章,但是在项目中却没用实际应用过。刚好这几天不忙,就看了下 Google 官方的 TODO-MVP-Loaders ,并仿照其更改了自己的项目。
- MVP 模式
M: Model - 业务逻辑和实体模型;
V: View - 对应于Activity或Fragment,负责UI 绘制及用户交互;
P: Presenter - 负责 M 和 V 的交互。
看下Google 官方图示
从中可以看出,Sample 采用了观察者模式,Fragment 作为 View 层,而 Activity 负责 View 和 Presenter 的创建并将二者关联起来,Repository 可以看作为 M 层,Loader 我理解为是M 层的助手,在 Loader 中注册 Repository 并监听数据源变化。
- TODO-MVP-Loaders Sample 架构
Sample 中主要有四个模块:
Tasks - 任务列表;
Addedittask - 新建任务;
Taskdetail - 任务编辑;
Statistics - 统计。
所有模块 Presenter 的基类
public interface BasePresenter{ void start();}
View 的基类
public interface BaseView<T>{ void setPresenter(T presenter);}
这里主要 分析 Tasks 模块,其余模块思想都是类似的。
- Tasks
从上图的图示中,我们可以看到在 data 包下有数据源 source 及实体类 task,而 source 中有 local 和 remote 两个子包,从包名上就可以猜出一个是本地存储一个是网络存储,分别打开后我们可以看到,分别对应有TasksLocalDataSource 和TasksRemoteDataSource 类,并且都实现了 TasksDataSource 接口,而该接口中主要定义了对任务数据的所有操作,如
@NullableList<Task> getTasks();@NullableTask getTask(@NonNull String taskId);void saveTask(@NonNull Task task);...
TasksRemoteDataSource 模拟网络数据操作,TasksLocalDataSource 采用SQLite数据库存储数据。由 MVP 模型定义我们可以知道,数据的逻辑处理是在 M 层中完成的,那么我们看下 M 都干了些什么活。
- TasksRepository 类
之前有说过,TasksRepository 作为 M 层,那么它中一定会进行数据处理,我们进去瞧瞧
public class TasksRepository implements TasksDataSource{ private List<TasksRepositoryObserver> mObservers = new ArrayList<>(); ... private TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource, @NonNull TasksDataSource tasksLocalDataSource) { mTasksRemoteDataSource = checkNotNull(tasksRemoteDataSource); mTasksLocalDataSource = checkNotNull(tasksLocalDataSource); } @Override public void saveTask(@NonNull Task task) { checkNotNull(task); mTasksRemoteDataSource.saveTask(task); mTasksLocalDataSource.saveTask(task); // Do in memory cache update to keep the app UI up to date if (mCachedTasks == null) { mCachedTasks = new LinkedHashMap<>(); } mCachedTasks.put(task.getId(), task); // Update the UI notifyContentObserver(); }}
可以看出,采用 List 存储 TasksRepositoryObserver ,构成方法中传入 LocalDataSource 和 RemoteDataSource 实例来实现对数据的变化监听。因为其也实现了 TasksDataSource 接口,所以在各种 task 操作时一定会调用 LocalDataSource 和 RemoteDataSource 中相应的操作。如
@Override public void completeTask(@NonNull Task task) { checkNotNull(task); mTasksRemoteDataSource.completeTask(task); mTasksLocalDataSource.completeTask(task); ... } @Override public void activateTask(@NonNull Task task) { checkNotNull(task); mTasksRemoteDataSource.activateTask(task); mTasksLocalDataSource.activateTask(task); ... } ...
可以看到确实调用了。M 层简要介绍完了,我们再看下 P 层
- P 层 - TasksPresenter 类
public class TasksPresenter implements TasksContract.Presenter, LoaderManager.LoaderCallbacks<List<Task>>{ public TasksPresenter(@NonNull TasksLoader loader, @NonNull LoaderManager loaderManager, @NonNull TasksRepository tasksRepository, @NonNull TasksContract.View tasksView) { mLoader = checkNotNull(loader, "loader cannot be null!"); mLoaderManager = checkNotNull(loaderManager, "loader manager cannot be null"); mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null"); mTasksView = checkNotNull(tasksView, "tasksView cannot be null!"); mTasksView.setPresenter(this); }}
P 层实现了 LoaderManager.LoaderCallbacks 接口,我们看看该接口中主要有哪些方法
//1public Loader<D> onCreateLoader(int id, Bundle args);//2public void onLoadFinished(Loader<D> loader, D data);//3public void onLoaderReset(Loader<D> loader);
onCreateLoader 方法返回一个 Loader ,貌似构造方法中传入了一个 Loader 实例吧,恩,确实传入了,进去看看这个类干的什么活。
- TaskLoader 和 TasksLoader 类
public class TaskLoader extends AsyncTaskLoader<Task> implements TasksRepository.TasksRepositoryObserver{ public TaskLoader(String taskId, Context context) { super(context); this.mTaskId = taskId; mRepository = Injection.provideTasksRepository(context); } @Override public Task loadInBackground() { //获取数据 return mRepository.getTask(mTaskId); } @Override protected void onStartLoading() { // Deliver any previously loaded data immediately if available. if (mRepository.cachedTasksAvailable()) { deliverResult(mRepository.getCachedTask(mTaskId)); } // Begin monitoring the underlying data source. mRepository.addContentObserver(this); if (takeContentChanged() || !mRepository.cachedTasksAvailable()) { // When a change has been delivered or the repository cache isn't available, we force // a load. forceLoad(); } } @Override protected void onReset() { onStopLoading(); mRepository.removeContentObserver(this); }}
TaskLoader 和 TasksLoader 都是继承 AsyncTaskLoader 并实现了 TasksRepository.TasksRepositoryObserver 接口。AsyncTaskLoader 是个抽象类,并且有个抽象方法
public abstract D loadInBackground();
看名字就知道,异步线程加载主要就是在这个方法中操作的。看看是不是这样呢?
TaskLoader 中
@Override public Task loadInBackground() { return mRepository.getTask(mTaskId); }
TasksLoader 中
@Override public List<Task> loadInBackground() { return mRepository.getTasks(); }
确实是在这里调用。同时在
@Override protected void onStartLoading() { // Deliver any previously loaded data immediately if available. if (mRepository.cachedTasksAvailable()) { deliverResult(mRepository.getCachedTasks()); } // Begin monitoring the underlying data source. mRepository.addContentObserver(this); ... }
方法中, 先是检查是否有缓存数据,如果有就直接交付了,并且在这里注册里观察者。
我们在接着看 P 层的构造函数, 其接收四个参数:
1. - TasksLoader - taskLoader 用于在
@Override public Loader<List<Task>> onCreateLoader(int id, Bundle args) { mTasksView.setLoadingIndicator(true); return mLoader; }
回调时返回该 taskLoader ;
2. - LoaderManager - loaderManager 用于在
@Override public void start() { mLoaderManager.initLoader(TASKS_QUERY, null, this); }
回调时初始化 Loader ;
3. - TasksRepository - asksRepository 监听数据变化;如
public void loadTasks(boolean forceUpdate) { ... mTasksRepository.refreshTasks(); ... }
4. - TasksContract.View - tasksView View 层实现类,其实现为 TaskFragment 既 V 层,到这里 MVP 三层都有了。
- 流程梳理
TasksActivity 中,主要就是干了一件事,哪一件呢?
// Create the presenter TasksRepository repository = Injection.provideTasksRepository(getApplicationContext()); TasksLoader tasksLoader = new TasksLoader(getApplicationContext(), repository); mTasksPresenter = new TasksPresenter( tasksLoader, getSupportLoaderManager(), repository, tasksFragment );
就是它,初始化了 Presenter。
TasksFragment 中
@Override public void onResume() { super.onResume(); mPresenter.start(); } @Override public void setPresenter(@NonNull TasksContract.Presenter presenter) { mPresenter = checkNotNull(presenter); }
Presenter 初始化后,将 Presenter 实例传入 View 层中,同时在 onResume() 方法中,调用 onStart()。
Presenter 中
当 onStart() 方法被调用后,LoaderManager 会立即初始化 Loader
@Override public void start() { mLoaderManager.initLoader(TASKS_QUERY, null, this); }
并在 onCreateLoader(int id, Bundle args) 方法中返回 Loader 实例
@Override public Loader<List<Task>> onCreateLoader(int id, Bundle args) { return mLoader; }
当 Loader 实例成功返回后会立即执行
@Override public Task loadInBackground() { //获取数据 }
数据成功获取后会调用 Presenter 中
@Override public void onLoadFinished(Loader<List<Task>> loader, List<Task> data) { //data 返回的数据 }
此时即可在 View 中展示并更新UI了。
- 后记
以上就是我对 Google TODO-MVP-Loaders 的理解,仿照其更改了自己的项目,现在在看起来比较顺眼多了。希望我的分析能对你有所帮助,同时欢迎大家指出文中不足之处,益于加强我对其理解,提升自己。
最合适的才是最好的,加油!!!
- Google TODO-MVP-Loaders 简要分析
- Google官方MVP示例之TODO-MVP
- Google官方MVP示例之TODO-MVP
- Google 的android-architecture,todo-mvp解析
- 从google的todo学习MVP
- Google官方MVP翻译示例之TODO-MVP
- Android 官方示例:android-architecture 学习笔记(三)之todo-mvp-loaders
- Android Todo MVP 框架分析和例子
- TODO-MVP源码解析
- 理解 todo-mvp-clean
- 【android-architecture】todo-mvp
- Android todo-mvp
- MVP google官方demo比较分析
- Android官方TODO-MVP项目分析(上)---View 层 Presenter 层以及 Contract 分析
- Android-Architecture之todo-mvp
- todo-mvp-clean简化版本
- Google-todo-clean读书笔记
- Loaders
- Python矩阵计算
- SecureCRT自动保存日志设置
- 拦截导弹 poj
- centos7 安装mysql(解压缩版)
- android内存优化知识
- Google TODO-MVP-Loaders 简要分析
- Java WebService 简单实例、调用第三方提供的WebService服务
- 模板函数的定义问题
- 南阳oj-58 最少步数
- sudo apt-get autoremove系统崩溃
- C++ allocators将构造函数,析构函数与分配内存解耦
- Problem E: 倒水(Water)
- python正则表达式search方法
- SQLite的使用—— Swift代码