MVP之Android官方MVP架构学习—Model层

一、Model层结构

Model层类位于data包下,组织结构如图:


MVP之Android官方MVP架构学习—Model层_第1张图片
model.jpg

二、Model层分析

1. 实体类

Tasks作为实体类,定义的属性和方法,具体可以查看代码

2. 接口

TasksDataSource定义了Model的回调接口和方法

public interface TasksDataSource {

    interface LoadTasksCallback {

        void onTasksLoaded(List 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);
}

3.实现类

3.1 TasksLocalDataSource

TasksLocalDataSource是TasksDataSource的本地数据源实现类,用于从本地数据库获取数据,采用单例模式,并且有两个帮助类TasksDbHelper和TasksPersistenceContract用于从操作数据库

3.1 TasksRemoteDataSource

TasksRemoteDataSource是TasksDataSource的远程数据源实现类,用于从服务端获取数据(demo里只是模仿从服务端获取),采用单例模式

3.1 TasksRepository

Repository也是TasksDataSource的实现类,其中持有两个两个TasksDataSource对象,一般为一个TasksLocalDataSource对象和一个TasksRemoteDataSource对象,用于统一管理获取数据的方式,采用单例模式

public class TasksRepository implements TasksDataSource {

    private static TasksRepository INSTANCE = null;

    // 远程数据源对象
    private final TasksDataSource mTasksRemoteDataSource;

    // 本地数据源对象
    private final TasksDataSource mTasksLocalDataSource;

    // 存放缓存数据
    Map mCachedTasks;

    // 缓存数据是否可用
    boolean mCacheIsDirty = false;

    // 构造方法
    private TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource,
                            @NonNull TasksDataSource tasksLocalDataSource) {
        mTasksRemoteDataSource = checkNotNull(tasksRemoteDataSource);
        mTasksLocalDataSource = checkNotNull(tasksLocalDataSource);
    }

    // 获取TasksRepository实例,采用单例模式
    public static TasksRepository getInstance(TasksDataSource tasksRemoteDataSource,
                                              TasksDataSource tasksLocalDataSource) {
        if (INSTANCE == null) {
            INSTANCE = new TasksRepository(tasksRemoteDataSource, tasksLocalDataSource);
        }
        return INSTANCE;
    }

    public static void destroyInstance() {
        INSTANCE = null;
    }

    // 获取数据
    @Override
    public void getTasks(@NonNull final LoadTasksCallback callback) {
        checkNotNull(callback);

        // 如果缓存可用,则立即返回内存中的数据
        if (mCachedTasks != null && !mCacheIsDirty) {
            callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
            return;
        }

        if (mCacheIsDirty) {
            // 如果缓存数据已经不可用,则从服务端更新数据
            getTasksFromRemoteDataSource(callback);
        } else {
            // 从数据库获取数据,如果没有,则从服务端获取
            mTasksLocalDataSource.getTasks(new LoadTasksCallback() {
                @Override
                public void onTasksLoaded(List tasks) {
                    refreshCache(tasks);
                    callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
                }

                @Override
                public void onDataNotAvailable() {
                    getTasksFromRemoteDataSource(callback);
                }
            });
        }
    }

    // 从服务端获取数据
    private void getTasksFromRemoteDataSource(@NonNull final LoadTasksCallback callback) {
        mTasksRemoteDataSource.getTasks(new LoadTasksCallback() {
            @Override
            public void onTasksLoaded(List tasks) {
                refreshCache(tasks);
                refreshLocalDataSource(tasks);
                callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values()));
            }

            @Override
            public void onDataNotAvailable() {
                callback.onDataNotAvailable();
            }
        });
    }
}

可以看到,在实例化TasksRepository时需要传入两个TasksDataSource对象;在获取数据时先从缓存中获取,如果缓存中没有,则从数据库获取,数据库没有,再从服务端获取,若为强制刷新,则直接从服务端获取。

三、Model使用

1.TasksDataSource的实例化

在MVP中,Presenter对象持有Model对象,如:

public class AddEditTaskPresenter implements AddEditTaskContract.Presenter,
        TasksDataSource.GetTaskCallback {

    // TasksDataSource对象
    @NonNull
    private final TasksDataSource mTasksRepository;

    // 实例化时传入TasksDataSource对象
    public AddEditTaskPresenter(@Nullable String taskId, @NonNull TasksDataSource tasksRepository,
            @NonNull AddEditTaskContract.View addTaskView) {
        mTaskId = taskId;
        mTasksRepository = checkNotNull(tasksRepository);
        mAddTaskView = checkNotNull(addTaskView);

        mAddTaskView.setPresenter(this);
    }
}

Presenter在实例化是需要传入TasksDataSource对象,Presenter是在Activity中完成实例化的

public class AddEditTaskActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.addtask_act);

        ...

        // 实例化Presenter,传入TasksDataSource对象
        new AddEditTaskPresenter(
                taskId,
                Injection.provideTasksRepository(getApplicationContext()),
                addEditTaskFragment);
    }
}

可以看到TasksDataSource对象是由Injection类的provideTasksRepository方法生成

2.Gradle动态配置

在main/java目中并没有Injection类,通过查看app/build.gradle文件可以知道,项目有两个生产版本:mock和prod,如下:

productFlavors {
        mock {
            applicationIdSuffix = ".mock"
        }
        prod {

        }
    }

在项目的目录结构中也有对应的src/mock和src/prod两个目录目录

MVP之Android官方MVP架构学习—Model层_第2张图片
source_directories.jpg

在mock和prod中�分别有一个Injection类,这里利用了gradle中的productFlavor创建了多个版本,其中每个版本都可以在工程src目录下建立与main同级的文件夹,文件夹名字就是ProductFlavor的名字,可以在其中创建java目录并添加相应的java文件,不用的版本可以有相同名字不同实现的类,具体可查看 Android Plugin for Gradle。
prod目录下的Injection

public class Injection {

    public static TasksRepository provideTasksRepository(@NonNull Context context) {
        checkNotNull(context);
        return TasksRepository.getInstance(TasksRemoteDataSource.getInstance(),
                TasksLocalDataSource.getInstance(context));
    }
}

mock目录下的Injection

public class Injection {

    public static TasksRepository provideTasksRepository(@NonNull Context context) {
        checkNotNull(context);
        return TasksRepository.getInstance(FakeTasksRemoteDataSource.getInstance(),
                TasksLocalDataSource.getInstance(context));
    }
}

可以看到:

  • prod的Injection创建TasksRepository实例时传入的是TasksRemoteDataSource实例和TasksLocalDataSource实例

  • mock的Injection创建TasksRepository实例时传入的是FakeTasksRemoteDataSource实例和TasksLocalDataSource实例,其中FakeTasksRemoteDataSource是在mock目录下创建的TasksDataSource的实现类。

通过这种方式可以实现不同版本注入不同的TasksDataSource实现类。

你可能感兴趣的:(MVP之Android官方MVP架构学习—Model层)