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 - 对应于ActivityFragment,负责UI 绘制及用户交互;
    P: Presenter - 负责 MV 的交互。
    看下Google 官方图示

MVP 图示

从中可以看出,Sample 采用了观察者模式,Fragment 作为 View 层,而 Activity 负责 ViewPresenter 的创建并将二者关联起来,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 中有 localremote 两个子包,从包名上就可以猜出一个是本地存储一个是网络存储,分别打开后我们可以看到,分别对应有TasksLocalDataSourceTasksRemoteDataSource 类,并且都实现了 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 ,构成方法中传入 LocalDataSourceRemoteDataSource 实例来实现对数据的变化监听。因为其也实现了 TasksDataSource 接口,所以在各种 task 操作时一定会调用 LocalDataSourceRemoteDataSource 中相应的操作。如

  @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 实例吧,恩,确实传入了,进去看看这个类干的什么活。

  • TaskLoaderTasksLoader
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);  }}

TaskLoaderTasksLoader 都是继承 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 层实现类,其实现为 TaskFragmentV 层,到这里 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 的理解,仿照其更改了自己的项目,现在在看起来比较顺眼多了。希望我的分析能对你有所帮助,同时欢迎大家指出文中不足之处,益于加强我对其理解,提升自己。
    最合适的才是最好的,加油!!!
0 0
原创粉丝点击