Google-todo-clean读书笔记
题外:从现在开始,坚持一次只看一个项目,并且做笔记。
首先,需要重新看一下Clean框架的体系:
Clean一般是指,代码以洋葱的形状依据一定的依赖规则被划分为多层:内层对于外层一无所知。这就意味着依赖只能由外向内。
用图表示如下。
关于clean 架构建议去看这个博客讲的,真的很清晰。
下面是摘抄自博客的:
一个Android应用通用结构如下:
- 外层包:UI、存储、网络
- 中间层:Presenter、Converter
- 内层包:Interactor、Model、Repository、Executor
外层:该层是框架的具体细节所在
UI :这是所有Activity、Fragment、适配模块和其他与用户接口相关的Android代码存在的地方。
存储 :Interactor访问和存储数据所需要使用的接口代码。例如,它包括了ContentProvider或者DBFlow等ORM。
网络——包括了Retrofit等。
中间层:负责将实现细节和业务逻辑连接起来的粘合层
- Presenter——Presenter负责处理来自UI的事件(如用户点击等)和内层模块(如Interaactor等)的回调。
- Converter——Converter对象负责内层模型与外层模块的相互转换工作。
内层:
该层包含了绝大部分高级代码。其中所有的类都是POJO。该层中的类和对象对于Android应用相关的东西一无所知,因此可以被轻易移植到任何运行JVM的机器中
Interactor——这就是包含实际的业务逻辑代码的类。他们在后台运行,并通过回调函数将事件报告给上层。在一些项目中,他们也被称作用例。通常情况下,项目中可能包含很多小的Interactor类,用来分别解决特定的问题。这符合了单一职责原则,也比较容易对类进行理解。
模型——这些就是在业务逻辑中进行处理的业务模型。
Repository——该包只包含了数据库或者其他外层实现的接口。Interactor使用这些接口来访问和存储数据。这就是所谓的repository模式.
现在以Todo-clean为例子,先看整体分包,可以看到是先根据模块分包,再根据职能分包:
接下来以TaskActivity为例子,给出各个层在代码中对应的类:
其实谷歌官方也说了,clean架构和mvp架构的区别在于,在p层和repositoies之间多了一个domain layer。
现在通过时序图来看一下调用taskPresener.loadTask()方法的过程:
我们可以看到,调用的过程的确是从外到内,再从内到外的。
从google这个官方的demo中,我们其实就可以抽取出一个简单的数据逻辑处理层的框架:
负责具体数据操作的UseCase基类:
/**
* Use cases are the entry points to the domain layer.
*
* @param <Q> the request type
* @param <P> the response type
*/
public abstract class UseCase<Q extends UseCase.RequestValues, P extends UseCase.ResponseValue> {
private Q mRequestValues;
private UseCaseCallback<P> mUseCaseCallback;
public void setRequestValues(Q requestValues) {
mRequestValues = requestValues;
}
public Q getRequestValues() {
return mRequestValues;
}
public UseCaseCallback<P> getUseCaseCallback() {
return mUseCaseCallback;
}
public void setUseCaseCallback(UseCaseCallback<P> useCaseCallback) {
mUseCaseCallback = useCaseCallback;
}
void run() {
executeUseCase(mRequestValues);
}
protected abstract void executeUseCase(Q requestValues);
/**
* Data passed to a request.
*/
public interface RequestValues {
}
/**
* Data received from a request.
*/
public interface ResponseValue {
}
public interface UseCaseCallback<R> {
void onSuccess(R response);
void onError();
}
}
UseCaseHandler
:负责进行UseCase和线程协调的类:
public class UseCaseHandler {
private static UseCaseHandler INSTANCE;
private final UseCaseScheduler mUseCaseScheduler;
public UseCaseHandler(UseCaseScheduler useCaseScheduler) {
mUseCaseScheduler = useCaseScheduler;
}
public <T extends UseCase.RequestValues, R extends UseCase.ResponseValue> void execute(
final UseCase<T, R> useCase, T values, UseCase.UseCaseCallback<R> callback) {
useCase.setRequestValues(values);
useCase.setUseCaseCallback(new UiCallbackWrapper(callback, this));
// The network request might be handled in a different thread so make sure
// Espresso knows
// that the app is busy until the response is handled.
EspressoIdlingResource.increment(); // App is busy until further notice
mUseCaseScheduler.execute(new Runnable() {
@Override
public void run() {
useCase.run();
// This callback may be called twice, once for the cache and once for loading
// the data from the server API, so we check before decrementing, otherwise
// it throws "Counter has been corrupted!" exception.
if (!EspressoIdlingResource.getIdlingResource().isIdleNow()) {
EspressoIdlingResource.decrement(); // Set app as idle.
}
}
});
}
public <V extends UseCase.ResponseValue> void notifyResponse(final V response,
final UseCase.UseCaseCallback<V> useCaseCallback) {
mUseCaseScheduler.notifyResponse(response, useCaseCallback);
}
private <V extends UseCase.ResponseValue> void notifyError(
final UseCase.UseCaseCallback<V> useCaseCallback) {
mUseCaseScheduler.onError(useCaseCallback);
}
private static final class UiCallbackWrapper<V extends UseCase.ResponseValue> implements
UseCase.UseCaseCallback<V> {
private final UseCase.UseCaseCallback<V> mCallback;
private final UseCaseHandler mUseCaseHandler;
public UiCallbackWrapper(UseCase.UseCaseCallback<V> callback,
UseCaseHandler useCaseHandler) {
mCallback = callback;
mUseCaseHandler = useCaseHandler;
}
@Override
public void onSuccess(V response) {
mUseCaseHandler.notifyResponse(response, mCallback);
}
@Override
public void onError() {
mUseCaseHandler.notifyError(mCallback);
}
}
public static UseCaseHandler getInstance() {
if (INSTANCE == null) {
INSTANCE = new UseCaseHandler(new UseCaseThreadPoolScheduler());
}
return INSTANCE;
}
}
UseCaseSchedule
:进行前后台线程切换的类:
public interface UseCaseScheduler {
void execute(Runnable runnable);
<V extends UseCase.ResponseValue> void notifyResponse(final V response,
final UseCase.UseCaseCallback<V> useCaseCallback);
<V extends UseCase.ResponseValue> void onError(
final UseCase.UseCaseCallback<V> useCaseCallback);
}
它的默认实现类:
public class UseCaseThreadPoolScheduler implements UseCaseScheduler {
private final Handler mHandler = new Handler();
public static final int POOL_SIZE = 2;
public static final int MAX_POOL_SIZE = 4;
public static final int TIMEOUT = 30;
ThreadPoolExecutor mThreadPoolExecutor;
public UseCaseThreadPoolScheduler() {
mThreadPoolExecutor = new ThreadPoolExecutor(POOL_SIZE, MAX_POOL_SIZE, TIMEOUT,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(POOL_SIZE));
}
@Override
public void execute(Runnable runnable) {
mThreadPoolExecutor.execute(runnable);
}
@Override
public <V extends UseCase.ResponseValue> void notifyResponse(final V response,
final UseCase.UseCaseCallback<V> useCaseCallback) {
mHandler.post(new Runnable() {
@Override
public void run() {
useCaseCallback.onSuccess(response);
}
});
}
@Override
public <V extends UseCase.ResponseValue> void onError(
final UseCase.UseCaseCallback<V> useCaseCallback) {
mHandler.post(new Runnable() {
@Override
public void run() {
useCaseCallback.onError();
}
});
}
}
好了,这几个类是在任何项目中都通用,可以封装到底层的。下面是使用的例子:
- 从最里面开始写起,先定义repository,也就是支持的数据操作:
public interface TasksDataSource {
interface LoadTasksCallback {
void onTasksLoaded(List<Task> tasks);
void onDataNotAvailable();
}
void getTasks(@NonNull LoadTasksCallback callback);
}
public class TasksRepository implements TasksDataSource{
private final TasksDataSource mTasksRemoteDataSource; //TasksDataSource的实现类,从网络获取数据
private final TasksDataSource mTasksLocalDataSource;//TasksDataSource的实现类,从数据库获取数据
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 {
getTasksFromLocalDataSource(callback);
}
}
}
2 定义UseCase,它里面包含Repository的实例:
public class GetTasks extends UseCase<GetTasks.RequestValues, GetTasks.ResponseValue> {
private final TasksRepository mTasksRepository;
private final FilterFactory mFilterFactory;
public GetTasks(@NonNull TasksRepository tasksRepository, @NonNull FilterFactory filterFactory) {
mTasksRepository = checkNotNull(tasksRepository, "tasksRepository cannot be null!");
mFilterFactory = checkNotNull(filterFactory, "filterFactory cannot be null!");
}
//自己定义的请求参数
public static final class RequestValues implements UseCase.RequestValues {
//请求参数
private final TasksFilterType mCurrentFiltering;
private final boolean mForceUpdate;
public RequestValues(boolean forceUpdate, @NonNull TasksFilterType currentFiltering) {
mForceUpdate = forceUpdate;
mCurrentFiltering = checkNotNull(currentFiltering, "currentFiltering cannot be null!");
}
public boolean isForceUpdate() {
return mForceUpdate;
}
public TasksFilterType getCurrentFiltering() {
return mCurrentFiltering;
}
}
//自己定义的返回参数
public static final class ResponseValue implements UseCase.ResponseValue {
//返回任务列表
private final List<Task> mTasks;
public ResponseValue(@NonNull List<Task> tasks) {
mTasks = checkNotNull(tasks, "tasks cannot be null!");
}
public List<Task> getTasks() {
return mTasks;
}
}
//重点是看对基类中executeUseCase(RequestValue)的实现:
protected void executeUseCase(final RequestValues values) {
if (values.isForceUpdate()) {
mTasksRepository.refreshTasks();
}
mTasksRepository.getTasks(new TasksDataSource.LoadTasksCallback() {
@Override
public void onTasksLoaded(List<Task> tasks) {
//取出请求参数
TasksFilterType currentFiltering = values.getCurrentFiltering();
//这两步可以根据请求参数去获取结果
TaskFilter taskFilter = mFilterFactory.create(currentFiltering);
List<Task> tasksFiltered = taskFilter.filter(tasks);
//最后将请求结果通过回调返回
ResponseValue responseValue = new ResponseValue(tasksFiltered);
getUseCaseCallback().onSuccess(responseValue);
}
@Override
public void onDataNotAvailable() {
getUseCaseCallback().onError();
}
});
}
}
3 最后只需要在presenter的方法中调用UseCaseHandler.execute
的方法,传入Usecase和请求参数就可以完成获取数据的操作啦。。。
mUseCaseHandler = UseCaseHandler.getInstance();//这里为了简单,就直接在这里实例化,最好还是从构造函数中传递进来,降低耦合,或者采用Dagger2进行注入
mUseCaseHandler.execute(mGetTasks, requestValue,我们自定义的回调);
准备把这一部分应用到项目中,虽然可能类写起来有点多。不过我自己觉得层次很清晰。