MVP(loader/dagger/rxjava2)

MVP概念
  • View
    视图层,包含各种界面相关功能,例如Activity,Fragment,View,Adapter,专注于交互,一般持有Presenter的引用,或者通过依赖注入(Dagger)方式获得Presenter实例,将非UI逻辑操作委托给Presenter
  • Presenter
    逻辑控制层,充当中间人,隔离View层,Model层,接收View层的数据请求,分发给Model层处理,监听Model处理结果,将结果反馈给View,实项界面的刷新
  • Model
    封装网络数据请求,本地数据请求,对Presenter提供简单易用的接口
  • MVP,MVC区别
    • MVP

      1、模型与视图完全分离,我们可以修改视图而不影响模型
      2、可以更高效地使用模型,因为所有的交互都发生在一个地方——Presenter内部
      3、我们可以将一个Presenter用于多个视图,而不需要改变Presenter的逻辑。这个特性非常的有用,因为视图的变化总是比模型的变化频繁
      4、如果我们把逻辑放在Presenter中,那么我们就可以脱离用户接口来测试这些逻辑(单元测试)

    • MVP优缺点 可以Mock一个实现了接口Contract.View的View对象便于测试,业务逻辑代码与View的隔离解耦 缺点:View中持有Presenter,Presenter中持有View,增加了复杂度,复杂业务中Presenter的代码会臃肿
    • MVC中Model和View直接通信的,View中会包含业务逻辑代码,Controller控制层通常在Activity中实现业务逻辑代理,操作Model,但是不操作View,对View无知,Model数据更新完对视图进行更新,用户得到反馈
    • MVC优缺点,逻辑代码在Controller中,模块化,业务逻辑代码更改后,不需要更新View,Model;测试困难,Activity包含业务代码,成为了Controller层,Model,View之间存在耦合 (以下项目来自android-architecture-todoapp)
      mvp
  • BaseView

    1
    2
    3
    public interface BaseView<T> {
    void setPresenter(T presenter);
    }
  • BasePresenter

    1
    2
    3
    public interface BasePresenter {
    void start();
    }
  • TaskContract接口包装Presenter,View

    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
    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();
    }
  • TaskPresenter 实现TaskContract.Presenter,持有TaskContract.View对象,在Activity中初始化并传入View,Model

    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
    public class TasksPresenter implements TasksContract.Presenter {
    private final TasksRepository mTasksRepository;
    private final TasksContract.View mTasksView;
    public TasksPresenter(@NonNull TasksRepository tasksRepository, @NonNull TasksContract.View tasksView) {
    mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null");
    mTasksView = checkNotNull(tasksView, "tasksView cannot be null!");

    //View必须实现TasksContract.View
    mTasksView.setPresenter(this);
    }

    mTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {
    @Override
    public void onTasksLoaded(List<Task> tasks) {
    List<Task> tasksToShow = new ArrayList<Task>();

    // This callback may be called twice, once for the cache and once for loading
    // We filter the tasks based on the requestType
    for (Task task : tasks) {
    switch (mCurrentFiltering) {
    case ALL_TASKS:
    tasksToShow.add(task);
    break;
    case ACTIVE_TASKS:
    if (task.isActive()) {
    tasksToShow.add(task);
    }
    break;
    case COMPLETED_TASKS:
    if (task.isCompleted()) {
    tasksToShow.add(task);
    }
    break;
    default:
    tasksToShow.add(task);
    break;
    }
    }
    // The view may not be able to handle UI updates anymore
    if (!mTasksView.isActive()) {
    return;
    }
    if (showLoadingUI) {
    mTasksView.setLoadingIndicator(false);
    }

    processTasks(tasksToShow);
    }

    @Override
    public void onDataNotAvailable() {
    // The view may not be able to handle UI updates anymore
    if (!mTasksView.isActive()) {
    return;
    }
    mTasksView.showLoadingTasksError();
    }
    });
  • TasksFragment 持有TasksContract.Presenter对象,并实现TasksContract.View,Fragment实例化后在Presenter中taskView.setPresenter(this),在taskView中通过Presenter获取数据,并在Presenter中刷新内容,在taskView中响应

    1
    2
    3
    4
    5
    6
    7
    public class TasksFragment extends Fragment implements TasksContract.View
    private TasksContract.Presenter mPresenter;

    @Override
    public void setPresenter(@NonNull TasksContract.Presenter presenter) {
    mPresenter = checkNotNull(presenter);
    }
  • TaskActivity

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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);

    //set filter
    mTasksPresenter.setFiltering(currentFiltering);
  • ToDoDatabase RoomDatabase包含一个Task表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Database(entities = {Task.class}, version = 1)
    public abstract class ToDoDatabase extends RoomDatabase {

    private static ToDoDatabase INSTANCE;

    public abstract TasksDao taskDao();

    private static final Object sLock = new Object();

    public static ToDoDatabase getInstance(Context context) {
    synchronized (sLock) {
    if (INSTANCE == null) {
    INSTANCE = Room.databaseBuilder(context.getApplicationContext(),
    ToDoDatabase.class, "Tasks.db")
    .build();
    }
    return INSTANCE;
    }
    }

    }
  • TasksDao

    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
    60
    61
    62
    63
    64
    65
    66
    67
    @Dao
    public interface TasksDao {
    /**
    * Select all tasks from the tasks table.
    *
    * @return all tasks.
    */
    @Query("SELECT * FROM Tasks")
    List<Task> getTasks();

    /**
    * Select a task by id.
    *
    * @param taskId the task id.
    * @return the task with taskId.
    */
    @Query("SELECT * FROM Tasks WHERE entryid = :taskId")
    Task getTaskById(String taskId);

    /**
    * Insert a task in the database. If the task already exists, replace it.
    *
    * @param task the task to be inserted.
    */
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertTask(Task task);

    /**
    * Update a task.
    *
    * @param task task to be updated
    * @return the number of tasks updated. This should always be 1.
    */
    @Update
    int updateTask(Task task);

    /**
    * Update the complete status of a task
    *
    * @param taskId id of the task
    * @param completed status to be updated
    */
    @Query("UPDATE tasks SET completed = :completed WHERE entryid = :taskId")
    void updateCompleted(String taskId, boolean completed);

    /**
    * Delete a task by id.
    *
    * @return the number of tasks deleted. This should always be 1.
    */
    @Query("DELETE FROM Tasks WHERE entryid = :taskId")
    int deleteTaskById(String taskId);

    /**
    * Delete all tasks.
    */
    @Query("DELETE FROM Tasks")
    void deleteTasks();

    /**
    * Delete all completed tasks from the table.
    *
    * @return the number of tasks deleted.
    */
    @Query("DELETE FROM Tasks WHERE completed = 1")
    int deleteCompletedTasks();
    }
  • TasksLocalDataSource

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @Override
    public void saveTask(@NonNull final Task task) {
    checkNotNull(task);
    Runnable saveRunnable = new Runnable() {
    @Override
    public void run() {
    mTasksDao.insertTask(task);
    }
    };
    mAppExecutors.diskIO().execute(saveRunnable);
    }
  • 保存数据

    1
    mTasksRepository.saveTask(new Task(title, description, mTaskId));
  • DiskIOThreadExecutor

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class DiskIOThreadExecutor implements Executor {

    private final Executor mDiskIO;

    public DiskIOThreadExecutor() {
    mDiskIO = Executors.newSingleThreadExecutor();
    }

    @Override
    public void execute(@NonNull Runnable command) {
    mDiskIO.execute(command);
    }
    }
mvp-loader
  • Presenter中持有View,Loader,LoaderManager(提供异步加载),Repository,当数据发生变化时,Loader自动刷新View

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class TasksPresenter implements TasksContract.Presenter,
    LoaderManager.LoaderCallbacks<List<Task>> {

    private final static int TASKS_QUERY = 1;

    private final TasksRepository mTasksRepository;

    private final TasksContract.View mTasksView;

    private final TasksLoader mLoader;

    private final LoaderManager mLoaderManager;
  • TaskRepository,在MVP中需要回调刷新View,而在Loader机制中自动刷新

    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
    private final TasksDataSource mTasksRemoteDataSource;
    private final TasksDataSource mTasksLocalDataSource;
    private List<TasksRepositoryObserver> mObservers = new ArrayList<TasksRepositoryObserver>();
    // Update the UI
    notifyContentObserver();
    ···

    //从缓存Map中获取数据
    Map<String, Task> mCachedTasks;
    public List<Task> getCachedTasks() {
    return mCachedTasks == null ? null : new ArrayList<>(mCachedTasks.values());
    }
    public Task getCachedTask(String taskId) {
    return mCachedTasks.get(taskId);
    }

    //获取任务
    @Nullable
    @Override
    public List<Task> getTasks() {
    List<Task> tasks = null;
    if (!mCacheIsDirty) {
    // Respond immediately with cache if available and not dirty
    if (mCachedTasks != null) {
    tasks = getCachedTasks();
    return tasks;
    } else {
    // Query the local storage if available.
    tasks = mTasksLocalDataSource.getTasks();
    }
    }
    // To simplify, we'll consider the local data source fresh when it has data.
    if (tasks == null || tasks.isEmpty()) {
    // Grab remote data if cache is dirty or local data not available.
    tasks = mTasksRemoteDataSource.getTasks();
    // We copy the data to the device so we don't need to query the network next time
    saveTasksInLocalDataSource(tasks);
    }

    processLoadedTasks(tasks);
    return getCachedTasks();

    }
  • Fragment中涉及Loader加载数据,自动刷新流程

    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
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
     //在Activity中对Loader,LoaderManager,Presenter实例化
    // Create the presenter
    TasksRepository repository = Injection.provideTasksRepository(getApplicationContext());
    TasksLoader tasksLoader = new TasksLoader(getApplicationContext(), repository);
    mTasksPresenter = new TasksPresenter(
    tasksLoader,
    getSupportLoaderManager(),
    repository,
    tasksFragment
    );

    //FragmentManager的performStart()中也有回调LoadFinished()针对有缓存数据时刷新View
    void performStart() {
    ···
    onStart();
    ···
    if (mLoaderManager != null) {
    mLoaderManager.doReportStart();
    }
    }

    //Fragment的onResume()对LoadManager进行初始化
    @Override
    public void onResume() {
    super.onResume();
    mPresenter.start();
    }

    //Presenter初始化
    @Override
    public void start() {
    mLoaderManager.initLoader(TASK_QUERY, null, this);
    }
    //LoadManager开始加载
    void start(){
    mLoader.startLoading();
    }
    //LoaderManager中加载完成后回调callOnLoadFinished
    void finishRetain() {
    ···
    callOnLoadFinished(mLoader, mData);
    }

    void reportStart() {
    if (mStarted) {
    if (mReportNextStart) {
    mReportNextStart = false;
    if (mHaveData && !mRetaining) {
    callOnLoadFinished(mLoader, mData);
    }
    }
    }
    }

    //Presenter加载数据
    public void loadTasks(boolean forceUpdate) {
    if (forceUpdate || mFirstLoad) {
    mFirstLoad = false;
    mTasksRepository.refreshTasks();
    } else {
    showFilteredTasks();
    }
    }

    //加载完成后
    @Override
    public void onLoadFinished(Loader<List<Task>> loader, List<Task> data) {
    mTasksView.setLoadingIndicator(false);

    mCurrentTasks = data;
    if (mCurrentTasks == null) {
    mTasksView.showLoadingTasksError();
    } else {
    showFilteredTasks();
    }
    }

    //Presenter处理数据返回结果
    private void processTasks(List<Task> tasks) {
    if (tasks.isEmpty()) {
    // Show a message indicating there are no tasks for that filter type.
    processEmptyTasks();
    } else {
    // Show the list of tasks
    mTasksView.showTasks(tasks);
    // Set the filter label's text.
    showFilterLabel();
    }
    }

    //Fragment显示数据
    @Override
    public void showTasks(List<Task> tasks) {
    mListAdapter.replaceData(tasks);

    mTasksView.setVisibility(View.VISIBLE);
    mNoTasksView.setVisibility(View.GONE);
    }
mvp-dagger
  • DaggerApplication 注入Activity,Fragment,Service,BroadService,ContentProvider等成员,并在相应类中的onCreate()/onAttach()/onCreate()/onReceive()/onCreate()注入

    1
    AndroidInjection.inject(this);
  • DaggerApplication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public abstract class DaggerApplication extends Application
    implements HasActivityInjector,
    HasFragmentInjector,
    HasServiceInjector,
    HasBroadcastReceiverInjector,
    HasContentProviderInjector {

    @Inject DispatchingAndroidInjector<Activity> activityInjector;
    @Inject DispatchingAndroidInjector<BroadcastReceiver> broadcastReceiverInjector;
    @Inject DispatchingAndroidInjector<Fragment> fragmentInjector;
    @Inject DispatchingAndroidInjector<Service> serviceInjector;
    @Inject DispatchingAndroidInjector<ContentProvider> contentProviderInjector;
  • ToDoApplication

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class ToDoApplication extends DaggerApplication {
    @Inject
    TasksRepository tasksRepository;

    @Override
    protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
    return DaggerAppComponent.builder().application(this).build();
    }

    @VisibleForTesting
    public TasksRepository getTasksRepository() {
    return tasksRepository;
    }
    }
  • ApplicationModule 通过AppComponent依赖注入,提供给子组件Context实例

    1
    2
    3
    4
    5
    6
    @Module
    public abstract class ApplicationModule {
    //expose Application as an injectable context
    @Binds
    abstract Context bindContext(Application application);
    }
  • AppComponent 在Dagger.Android中自动生成并定位子组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    @Singleton
    @Component(modules = {TasksRepositoryModule.class,
    ApplicationModule.class,
    ActivityBindingModule.class,
    AndroidSupportInjectionModule.class})
    public interface AppComponent extends AndroidInjector<ToDoApplication> {

    TasksRepository getTasksRepository();

    // Gives us syntactic sugar. we can then do DaggerAppComponent.builder().application(this).build().inject(this);
    // never having to instantiate any modules or say which module we are passing the application to.
    // Application will just be provided into our app graph now.
    @Component.Builder
    interface Builder {

    @BindsInstance
    AppComponent.Builder application(Application application);

    AppComponent build();
    }
    }
  • TasksRepositoryModule

    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
    @Module
    abstract public class TasksRepositoryModule {

    private static final int THREAD_COUNT = 3;

    @Singleton
    @Binds
    @Local
    abstract TasksDataSource provideTasksLocalDataSource(TasksLocalDataSource dataSource);

    @Singleton
    @Binds
    @Remote
    abstract TasksDataSource provideTasksRemoteDataSource(FakeTasksRemoteDataSource dataSource);

    @Singleton
    @Provides
    static ToDoDatabase provideDb(Application context) {
    return Room.databaseBuilder(context.getApplicationContext(), ToDoDatabase.class, "Tasks.db")
    .build();
    }

    @Singleton
    @Provides
    static TasksDao provideTasksDao(ToDoDatabase db) {
    return db.taskDao();
    }

    @Singleton
    @Provides
    static AppExecutors provideAppExecutors() {
    return new AppExecutors(new DiskIOThreadExecutor(),
    Executors.newFixedThreadPool(THREAD_COUNT),
    new AppExecutors.MainThreadExecutor());
    }
    }
  • AppExecutors

    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
    @Singleton
    public class AppExecutors {

    private static final int THREAD_COUNT = 3;

    private final Executor diskIO;

    private final Executor networkIO;

    private final Executor mainThread;

    public AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
    this.diskIO = diskIO;
    this.networkIO = networkIO;
    this.mainThread = mainThread;
    }

    public Executor diskIO() {
    return diskIO;
    }

    public Executor networkIO() {
    return networkIO;
    }

    public Executor mainThread() {
    return mainThread;
    }

    public static class MainThreadExecutor implements Executor {
    private Handler mainThreadHandler = new Handler(Looper.getMainLooper());

    @Override
    public void execute(@NonNull Runnable command) {
    mainThreadHandler.post(command);
    }
    }
    }
  • TasksModule中的Presenter和View注入到TasksActivity,提供实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Module
    public abstract class TasksModule {
    @FragmentScoped
    @ContributesAndroidInjector
    abstract TasksFragment tasksFragment();

    @ActivityScoped
    @Binds abstract TasksContract.Presenter taskPresenter(TasksPresenter presenter);
    }
  • ActivityBindingModule,Android 注解处理器自动通过指定的模块生成子组件,并绑定AppComponent父组件,不需要告诉父组件子组件有哪些,也不需要告诉子组件谁是父组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    @Module
    public abstract class ActivityBindingModule {
    @ActivityScoped
    @ContributesAndroidInjector(modules = TasksModule.class)
    abstract TasksActivity tasksActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = AddEditTaskModule.class)
    abstract AddEditTaskActivity addEditTaskActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = StatisticsModule.class)
    abstract StatisticsActivity statisticsActivity();

    @ActivityScoped
    @ContributesAndroidInjector(modules = TaskDetailPresenterModule.class)
    abstract TaskDetailActivity taskDetailActivity();
    }
  • TasksActivity

    1
    2
    3
    4
    5
    6
    public class TasksActivity extends DaggerAppCompatActivity {
    @Inject
    TasksPresenter mTasksPresenter;
    @Inject
    Lazy<TasksFragment> taskFragmentProvider;
    }
  • TasksFragment

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @ActivityScoped
    public class TasksFragment extends DaggerFragment implements TasksContract.View {
    @Inject
    TasksContract.Presenter mPresenter;

    @Inject
    public TasksFragment() {
    // Requires empty public constructor
    }
  • TasksPresenter

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @ActivityScoped
    final class TasksPresenter implements TasksContract.Presenter {
    private final TasksRepository mTasksRepository;
    @Nullable
    private TasksContract.View mTasksView;

    @Inject
    TasksPresenter(TasksRepository tasksRepository) {
    mTasksRepository = tasksRepository;
    }
  • TasksRepository

    1
    2
    3
    4
    5
    6
    7
    8
    9
    @Singleton
    public class TasksRepository implements TasksDataSource {
    @Inject
    TasksRepository(@Remote TasksDataSource
    tasksRemoteDataSource,
    @Local TasksDataSource tasksLocalDataSource) {
    mTasksRemoteDataSource = tasksRemoteDataSource;
    mTasksLocalDataSource = tasksLocalDataSource;
    }
  • 在TasksActivity中通过依赖注入@Inject,TasksPresenter,TasksRepository,TasksFragment已经实例化

  • ActivityScope,FragmentScope

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Documented
    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    public @interface ActivityScoped {
    }

    @Scope
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE, ElementType.METHOD})
    public @interface FragmentScoped {}
  • ToDoDatabase

    1
    2
    3
    4
    @Database(entities = {Task.class}, version = 1)
    public abstract class ToDoDatabase extends RoomDatabase {
    public abstract TasksDao taskDao();
    }
mvp-rxjava2
  • BaseView

    1
    2
    3
    public interface BaseView<T> {
    void setPresenter(T presenter);
    }
  • BasePresenter

    1
    2
    3
    4
    public interface BasePresenter {
    void subscribe();
    void unsubscribe();
    }
  • 同样,在TasksActivity中持有TasksPresenter

    1
    2
    3
    4
    5
    // Create the presenter
    mTasksPresenter = new TasksPresenter(
    Injection.provideTasksRepository(getApplicationContext()),
    tasksFragment,
    Injection.provideSchedulerProvider());
  • TasksPresenter 持有TasksFragment对象mTasksView,网络请求等任务的集合CompositeDisposable,用于取消任务,避免内存泄漏

    • TasksPresenter

      1
      2
      3
      4
      5
      6
      7
      8
      9
      @Override
      public void subscribe() {
      loadTasks(false);
      }

      @Override
      public void unsubscribe() {
      mCompositeDisposable.clear();
      }
    • 对应的在TasksFragment

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      @Override
      public void onResume() {
      super.onResume();
      mPresenter.subscribe();
      }

      @Override
      public void onPause() {
      super.onPause();
      mPresenter.unsubscribe();
      }

      用于关联View,Presenter
      mTasksView.setPresenter(tasksPresenter);
  • TasksRepository获取Tasks

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    @Override
    public Flowable<List<Task>> getTasks() {
    // Respond immediately with cache if available and not dirty
    if (mCachedTasks != null && !mCacheIsDirty) {
    return Flowable.fromIterable(mCachedTasks.values()).toList().toFlowable();
    } else if (mCachedTasks == null) {
    mCachedTasks = new LinkedHashMap<>();
    }

    Flowable<List<Task>> remoteTasks = getAndSaveRemoteTasks();

    if (mCacheIsDirty) {
    return remoteTasks;
    } else {
    // Query the local storage if available. If not, query the network.
    Flowable<List<Task>> localTasks = getAndCacheLocalTasks();
    return Flowable.concat(localTasks, remoteTasks)
    .filter(tasks -> !tasks.isEmpty())
    .firstOrError()
    .toFlowable();
    }
    }
  • TasksPresenter中获取数据

    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
    mCompositeDisposable.clear();
    Disposable disposable = mTasksRepository
    .getTasks()
    .flatMap(Flowable::fromIterable)
    .filter(task -> {
    switch (mCurrentFiltering) {
    case ACTIVE_TASKS:
    return task.isActive();
    case COMPLETED_TASKS:
    return task.isCompleted();
    case ALL_TASKS:
    default:
    return true;
    }
    })
    .toList()
    .subscribeOn(mSchedulerProvider.io())
    .observeOn(mSchedulerProvider.ui())
    .doFinally(() -> {
    if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {
    EspressoIdlingResource.decrement(); // Set app as idle.
    }
    })
    .subscribe(
    // onNext
    tasks -> {
    processTasks(tasks);
    mTasksView.setLoadingIndicator(false);
    },
    // onError
    throwable -> mTasksView.showLoadingTasksError());

    mCompositeDisposable.add(disposable);
  • 处理返回数据,更新UI

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    TasksPresenter.java
    private void processTasks(@NonNull List<Task> tasks) {
    if (tasks.isEmpty()) {
    // Show a message indicating there are no tasks for that filter type.
    processEmptyTasks();
    } else {
    // Show the list of tasks
    mTasksView.showTasks(tasks);
    // Set the filter label's text.
    showFilterLabel();
    }
    }

    TasksFragment.java
    @Override
    public void showTasks(List<Task> tasks) {
    mListAdapter.replaceData(tasks);
    mTasksView.setVisibility(View.VISIBLE);
    mNoTasksView.setVisibility(View.GONE);
    }
willkernel wechat
关注微信公众号
帅哥美女们,请赐予我力量吧!