一、Model层结构
Model层类位于data包下,组织结构如图:
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两个目录目录
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实现类。