}//获取单个任务回调
void getTasks(@NonNull LoadTasksCallback callback);
void getTask(@NonNull String taskId, @NonNull GetTaskCallback callback);
void saveTask(@NonNull Task task);//保存数据
void refreshTasks();//刷新数据
void deleteAllTasks();//删除全部数据
void deleteTask(@NonNull String taskId);//删除单个任务数据 }
上面定义了数据源类TasksDataSource在这个类中定义了获取任务或者任务组的回调,已经获取任务,存储任务,删除任务,刷新任务的方法。其中的task是自定义的应用中要用到的数据类型,这里定义的比较简单:
public final class Task {
@PrimaryKey @NonNull @ColumnInfo(name = "entryid") private final String mId;//任务Id也是唯一键
@Nullable @ColumnInfo(name = "title") private final String mTitle;//任务标题
@Nullable @ColumnInfo(name = "description") private final String mDescription;//任务描述
public Task(@Nullable String title, @Nullable String description, @NonNull String id) { mId = id; mTitle = title; mDescription = description; }
}
因为Task要写入到本地数据库,所以mId作为唯一键。有了数据来源再定义本地数据仓库,数据仓库向activity提供数据,并且实现上面的三级缓存原理。数据仓库中处理三种来源的数据,并将最后的结果返回。 数据仓库TasksRepository
public class
TasksRepository implements TasksDataSource {
private static TasksRepository INSTANCE = null;
private final TasksDataSource mTasksRemoteDataSource;//服务器数据来源
private final TasksDataSource mTasksLocalDataSource;//本地数据库数据源
Map<String, Task> mCachedTasks;//内存缓存
boolean mCacheIsDirty = false;//标记缓存数据是否脏
// Prevent direct instantiation. private TasksRepository(@NonNull TasksDataSource tasksRemoteDataSource, @NonNull TasksDataSource tasksLocalDataSource) { mTasksRemoteDataSource = checkNotNull(tasksRemoteDataSource); mTasksLocalDataSource = checkNotNull(tasksLocalDataSource); }
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);
// Respond immediately with cache if available and not dirty if (mCachedTasks != null && !mCacheIsDirty) { callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values())); return; }
if (mCacheIsDirty) { // If the cache is dirty we need to fetch new data from the network. getTasksFromRemoteDataSource(callback); } else { // Query the local storage if available. If not, query the network. mTasksLocalDataSource.getTasks(new LoadTasksCallback() { @Override public void onTasksLoaded(List tasks) { refreshCache(tasks); callback.onTasksLoaded(new ArrayList<>(mCachedTasks.values())); }
@Override public void onDataNotAvailable() { getTasksFromRemoteDataSource(callback); } }); } } //保存任务 @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); } //通过taskid获取任务 @Override public void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) { checkNotNull(taskId); checkNotNull(callback);
Task cachedTask = getTaskWithId(taskId);
// Respond immediately with cache if available if (cachedTask != null) { callback.onTaskLoaded(cachedTask); return; }
// Load from server/persisted if needed.
// Is the task in the local data source? If not, query the network. mTasksLocalDataSource.getTask(taskId, new GetTaskCallback() { @Override public void onTaskLoaded(Task 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); callback.onTaskLoaded(task); }
@Override public void onDataNotAvailable() { mTasksRemoteDataSource.getTask(taskId, new GetTaskCallback() { @Override public void onTaskLoaded(Task 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); callback.onTaskLoaded(task); }
@Override public void onDataNotAvailable() { callback.onDataNotAvailable(); } }); } }); } //刷新任务 @Override public void refreshTasks() { mCacheIsDirty = true; } //删除全部任务 @Override public void deleteAllTasks() { mTasksRemoteDataSource.deleteAllTasks(); mTasksLocalDataSource.deleteAllTasks();
if (mCachedTasks == null) { mCachedTasks = new LinkedHashMap<>(); } mCachedTasks.clear(); } //删除任务 @Override public void deleteTask(@NonNull String taskId) { mTasksRemoteDataSource.deleteTask(checkNotNull(taskId)); mTasksLocalDataSource.deleteTask(checkNotNull(taskId));
mCachedTasks.remove(taskId); } //从服务器获取数据 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(); } }); } //刷新缓存数据 private void refreshCache(List tasks) { if (mCachedTasks == null) { mCachedTasks = new LinkedHashMap<>(); } mCachedTasks.clear(); for (Task task : tasks) { mCachedTasks.put(task.getId(), task); } mCacheIsDirty = false; } //刷新本地数据库 private void refreshLocalDataSource(List tasks) { mTasksLocalDataSource.deleteAllTasks(); for (Task task : tasks) { mTasksLocalDataSource.saveTask(task); } }
}
本地数据来源类TasksLocalDataSource
public class TasksLocalDataSource implements TasksDataSource {
private static volatile TasksLocalDataSource INSTANCE;
private TasksDao mTasksDao;
private AppExecutors mAppExecutors;
// Prevent direct instantiation. private TasksLocalDataSource(@NonNull AppExecutors appExecutors, @NonNull TasksDao tasksDao) { mAppExecutors = appExecutors; mTasksDao = tasksDao; }
public static TasksLocalDataSource getInstance(@NonNull AppExecutors appExecutors, @NonNull TasksDao tasksDao) { if (INSTANCE == null) { synchronized (TasksLocalDataSource.class) { if (INSTANCE == null) { INSTANCE = new TasksLocalDataSource(appExecutors, tasksDao); } } } return INSTANCE; }
/**
- Note: {@link LoadTasksCallback#onDataNotAvailable()} is fired if the database doesn't exist
- or the table is empty. */ @Override public void getTasks(@NonNull final LoadTasksCallback callback) { Runnable runnable = new Runnable() { @Override public void run() { final List tasks = mTasksDao.getTasks(); mAppExecutors.mainThread().execute(new Runnable() { @Override public void run() { if (tasks.isEmpty()) { // This will be called if the table is new or just empty. callback.onDataNotAvailable(); } else { callback.onTasksLoaded(tasks); } } }); } };
mAppExecutors.diskIO().execute(runnable); }
/**
- Note: {@link GetTaskCallback#onDataNotAvailable()} is fired if the {@link Task} isn't
- found. */ @Override public void getTask(@NonNull final String taskId, @NonNull final GetTaskCallback callback) { Runnable runnable = new Runnable() { @Override public void run() { final Task task = mTasksDao.getTaskById(taskId);
mAppExecutors.mainThread().execute(new Runnable() { @Override public void run() { if (task != null) { callback.onTaskLoaded(task); } else { callback.onDataNotAvailable(); } } }); } };
mAppExecutors.diskIO().execute(runnable); }
@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); }
@Override public void completeTask(@NonNull final Task task) { Runnable completeRunnable = new Runnable() { @Override public void run() { mTasksDao.updateCompleted(task.getId(), true); } };
mAppExecutors.diskIO().execute(completeRunnable); }
@Override public void completeTask(@NonNull String taskId) { // Not required for the local data source because the {@link TasksRepository} handles // converting from a {@code taskId} to a {@link task} using its cached data. }
@Override public void activateTask(@NonNull final Task task) { Runnable activateRunnable = new Runnable() { @Override public void run() { mTasksDao.updateCompleted(task.getId(), false); } }; mAppExecutors.diskIO().execute(activateRunnable); }
@Override public void activateTask(@NonNull String taskId) { // Not required for the local data source because the {@link TasksRepository} handles // converting from a {@code taskId} to a {@link task} using its cached data. }
@Override public void clearCompletedTasks() { Runnable clearTasksRunnable = new Runnable() { @Override public void run() { mTasksDao.deleteCompletedTasks();
} };
mAppExecutors.diskIO().execute(clearTasksRunnable); }
@Override public void refreshTasks() { // Not required because the {@link TasksRepository} handles the logic of refreshing the // tasks from all the available data sources. }
@Override public void deleteAllTasks() { Runnable deleteRunnable = new Runnable() { @Override public void run() { mTasksDao.deleteTasks(); } };
mAppExecutors.diskIO().execute(deleteRunnable); }
@Override public void deleteTask(@NonNull final String taskId) { Runnable deleteRunnable = new Runnable() { @Override public void run() { mTasksDao.deleteTaskById(taskId); } };
mAppExecutors.diskIO().execute(deleteRunnable); }
@VisibleForTesting static void clearInstance() { INSTANCE = null; } }
服务器数据来源类:FakeTasksRemoteDataSource
public class FakeTasksRemoteDataSource implements TasksDataSource {
由于篇幅原因,这份面试宝典已经被整理成了PDF文档,有需要Android面试宝典全套完整文档的麻烦点赞+点击GitHub即可获取资料免费领取方式!
本文在开源项目:GitHub中已收录,里面包含不同方向的自学编程路线、面试题集合/面经、及系列技术文章等,资源持续更新中...