package com.shizhefei.task; import android.text.TextUtils; import com.shizhefei.mvc.IAsyncDataSource; import com.shizhefei.mvc.IDataSource; import com.shizhefei.mvc.RequestHandle; import com.shizhefei.task.imp.MemoryCacheStore; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; /** * Created by LuckyJayce on 2016/7/17. * TaskHelper用于执行多个Task * 可以缓存数据 * * @param <BASE_DATA> 基础类型,execute的task的数据类型都继承于它,不是它的子类型的数据的task不能被执行 * 为什么要定义它?主要用于registerCallBack 注册全局的callback数据的返回的数据不用强制转化, */ public class TaskHelper<BASE_DATA> implements RequestHandle { private ICacheStore cacheStore; private Set<ICallback<BASE_DATA>> callBacks = new LinkedHashSet<>(); private List<MultiTaskBindProxyCallBack<?, BASE_DATA>> taskImps = new LinkedList<>(); public TaskHelper() { this(new MemoryCacheStore(100)); } public TaskHelper(ICacheStore cacheStore) { this.cacheStore = cacheStore; } public ICacheStore getCacheStore() { return cacheStore; } // public <DATA extends BASE_DATA> TaskHandle execute(ITask<DATA> task, ICallback<? super DATA> callBack) { // return executeImp(null, task, true, callBack); // } public <DATA extends BASE_DATA> TaskHandle execute(ITask<DATA> task, ICallback<DATA> callBack) { return executeImp(null, task, true, callBack); } public <DATA extends BASE_DATA> TaskHandle execute(final IDataSource<DATA> dataSource, ICallback<DATA> callBack) { return executeImp(null, dataSource, true, callBack); } public <DATA extends BASE_DATA> TaskHandle execute(final IDataSource<DATA> dataSource, boolean isExeRefresh, ICallback<DATA> callBack) { return executeImp(null, dataSource, isExeRefresh, callBack); } public <DATA extends BASE_DATA> TaskHandle execute(final IAsyncDataSource<DATA> dataSource, ICallback<DATA> callBack) { return executeImp(null, dataSource, true, callBack); } public <DATA extends BASE_DATA> TaskHandle execute(final IAsyncDataSource<DATA> dataSource, boolean isExeRefresh, ICallback<DATA> callBack) { return executeImp(null, dataSource, isExeRefresh, callBack); } public <DATA extends BASE_DATA> TaskHandle execute(IAsyncTask<DATA> task, ICallback<DATA> callBack) { return executeImp(null, task, true, callBack); } public <DATA extends BASE_DATA> TaskHandle executeCache(IAsyncDataSource<DATA> task, ICallback<DATA> callBack, ICacheConfig<DATA> cacheConfig) { return executeImp(cacheConfig, task, true, callBack); } public <DATA extends BASE_DATA> TaskHandle executeCache(ITask<DATA> task, ICallback<DATA> callBack, ICacheConfig<DATA> cacheConfig) { return executeImp(cacheConfig, task, true, callBack); } public <DATA extends BASE_DATA> TaskHandle executeCache(IAsyncTask<DATA> task, ICallback<DATA> callBack, ICacheConfig<DATA> cacheConfig) { return executeImp(cacheConfig, task, true, callBack); } public <DATA extends BASE_DATA> TaskHandle executeCache(IDataSource<DATA> task, ICallback<DATA> callBack, ICacheConfig<DATA> cacheConfig) { return executeImp(cacheConfig, task, true, callBack); } private <DATA extends BASE_DATA> MultiTaskBindProxyCallBack<DATA, BASE_DATA> getTaskImpByTask(String taskKey) { for (MultiTaskBindProxyCallBack<?, BASE_DATA> multiTaskBindProxyCallBack : taskImps) { if (taskKey.equals(multiTaskBindProxyCallBack.taskKey)) { return (MultiTaskBindProxyCallBack<DATA, BASE_DATA>) multiTaskBindProxyCallBack; } } return null; } private <DATA extends BASE_DATA> TaskHandle executeImp(ICacheConfig<DATA> cacheConfig, ISuperTask<DATA> task, boolean isExeRefresh, ICallback<DATA> callBack) { if (task == null) { throw new RuntimeException("task不能为空"); } if (cacheConfig != null) { String taskKey = cacheConfig.getTaskKey(task); if (TextUtils.isEmpty(taskKey)) { throw new RuntimeException("ICacheConfig 返回的taskkey不能为空"); } MultiTaskBindProxyCallBack<DATA, BASE_DATA> multiTaskBindProxyCallBack = getTaskImpByTask(taskKey); if (multiTaskBindProxyCallBack != null) { callBack.onPreExecute(task); multiTaskBindProxyCallBack.addCallBack(task, callBack); return new TaskHandle(TaskHandle.TYPE_ATTACH, task, multiTaskBindProxyCallBack); } } TaskHandle requestHandle = loadCache(cacheConfig, task, callBack); if (requestHandle == null) { MultiTaskBindProxyCallBack<DATA, BASE_DATA> multiTaskBindProxyCallBack = new MultiTaskBindProxyCallBack<>(cacheConfig, task, callBack, callBacks, taskImps, cacheStore); TaskExecutor<DATA> taskExecutor; if (task instanceof IDataSource) { taskExecutor = TaskExecutors.create((IDataSource<DATA>) task, isExeRefresh, multiTaskBindProxyCallBack); } else if (task instanceof IAsyncDataSource) { taskExecutor = TaskExecutors.create((IAsyncDataSource<DATA>) task, isExeRefresh, multiTaskBindProxyCallBack); } else if (task instanceof ITask) { taskExecutor = TaskExecutors.create((ITask<DATA>) task, multiTaskBindProxyCallBack); } else { taskExecutor = TaskExecutors.create((IAsyncTask<DATA>) task, multiTaskBindProxyCallBack); } multiTaskBindProxyCallBack.taskExecutor = taskExecutor; taskImps.add(multiTaskBindProxyCallBack); taskExecutor.execute(); requestHandle = new TaskHandle(TaskHandle.TYPE_RUN, task, multiTaskBindProxyCallBack); } return requestHandle; } private <DATA extends BASE_DATA> TaskHandle loadCache(ICacheConfig<DATA> cacheConfig, Object task, ICallback<DATA> callBack) { if (cacheConfig != null) { String taskKey = cacheConfig.getTaskKey(task); ICacheStore.Cache cache = cacheStore.getCache(taskKey); if (cache != null) { DATA data = (DATA) cache.data; if (cacheConfig.isUsefulCacheData(task, cache.requestTime, cache.saveTime, data)) { callBack.onPreExecute(task); callBack.onPostExecute(task, Code.SUCCESS, null, data); return new TaskHandle(TaskHandle.TYPE_CACHE, callBack, null); } } return null; } return null; } public void cancel(Object task) { if (task == null) { return; } if (task instanceof TaskHandle) { TaskHandle handle = (TaskHandle) task; handle.cancle(); return; } for (MultiTaskBindProxyCallBack<?, BASE_DATA> taskImp : taskImps) { if (taskImp.cancel(task)) { break; } } } public void cancelAllWithTaskKey(String taskKey) { if (TextUtils.isEmpty(taskKey)) { return; } MultiTaskBindProxyCallBack taskImp = getTaskImpByTask(taskKey); if (taskImp != null) { taskImp.cancelAllTaskBinder(); } } public void registerCallBack(ICallback<BASE_DATA> callback) { callBacks.add(callback); } public void unRegisterCallBack(ICallback<BASE_DATA> callback) { callBacks.remove(callback); } public void cancelAll() { if (taskImps.isEmpty()) { return; } //这里创建一个临时的map,主要原因是Set循环的时候不能remove操作,否则会报ConcurrentModificationException //TaskImp里面会调用到Set的remove HashSet<MultiTaskBindProxyCallBack<?, BASE_DATA>> temp = new HashSet<>(taskImps); for (MultiTaskBindProxyCallBack<?, BASE_DATA> entry : temp) { entry.cancelAllTaskBinder(); } taskImps.clear(); } public void destroy() { cancelAll(); } @Override public void cancle() { cancelAll(); } @Override public boolean isRunning() { return false; } static class MultiTaskBindProxyCallBack<DATA extends BASE_DATA, BASE_DATA> implements ICallback<DATA> { private ICallback<DATA> callback; private long requestTime; private Set<ICallback<BASE_DATA>> callbacks; private Map<Object, ICallback<DATA>> selfCallBacks = new LinkedHashMap<>(); private List<MultiTaskBindProxyCallBack<?, BASE_DATA>> taskImps; private ICacheStore cacheStore; private String taskKey; private ICacheConfig<DATA> cacheConfig; private Object realTask; private TaskExecutor<DATA> taskExecutor; public MultiTaskBindProxyCallBack(ICacheConfig<DATA> cacheConfig, Object realTask, ICallback<DATA> callback, Set<ICallback<BASE_DATA>> callbacks, List<MultiTaskBindProxyCallBack<?, BASE_DATA>> taskImps, ICacheStore cacheStore) { this.cacheConfig = cacheConfig; this.requestTime = System.currentTimeMillis(); if (cacheConfig != null) { this.taskKey = cacheConfig.getTaskKey(realTask); } this.callback = callback; this.callbacks = callbacks; this.taskImps = taskImps; this.cacheStore = cacheStore; this.realTask = realTask; } @Override public void onPreExecute(Object task) { for (Map.Entry<Object, ICallback<DATA>> callbackEntry : selfCallBacks.entrySet()) { Object aTask = callbackEntry.getKey(); ICallback<DATA> aCallback = callbackEntry.getValue(); aCallback.onPreExecute(aTask); } if (callback != null) { callback.onPreExecute(task); } for (ICallback<BASE_DATA> callback : callbacks) { callback.onPreExecute(task); } } @Override public void onProgress(Object task, int percent, long current, long total, Object extraData) { for (Map.Entry<Object, ICallback<DATA>> callbackEntry : selfCallBacks.entrySet()) { Object aTask = callbackEntry.getKey(); ICallback<DATA> aCallback = callbackEntry.getValue(); aCallback.onProgress(aTask, percent, current, total, extraData); } if (callback != null) { callback.onProgress(task, percent, current, total, extraData); } for (ICallback<BASE_DATA> callback : callbacks) { callback.onProgress(task, percent, current, total, extraData); } } @Override public void onPostExecute(Object task, Code code, Exception exception, DATA data) { for (Map.Entry<Object, ICallback<DATA>> taskCallbackEntry : selfCallBacks.entrySet()) { Object aTask = taskCallbackEntry.getKey(); ICallback<DATA> aCallback = taskCallbackEntry.getValue(); aCallback.onPostExecute(aTask, code, exception, data); } if (callback != null) { callback.onPostExecute(task, code, exception, data); } for (ICallback<BASE_DATA> callback : callbacks) { callback.onPostExecute(task, code, exception, data); } taskImps.remove(this); if (code == Code.SUCCESS) { if (cacheConfig != null) { long saveTime = System.currentTimeMillis(); if (cacheConfig.isNeedSave(task, requestTime, saveTime, data)) { String taskKey = cacheConfig.getTaskKey(task); cacheStore.saveCache(taskKey, requestTime, saveTime, data); } } } this.cacheStore = null; this.callbacks = null; this.cacheConfig = null; this.taskExecutor = null; this.taskImps = null; this.callback = null; this.selfCallBacks = null; this.realTask = null; this.taskKey = null; } public Map<Object, ICallback<DATA>> getCallbacks() { return selfCallBacks; } public void addCallBack(Object task, ICallback<DATA> callBack) { if (selfCallBacks != null) { selfCallBacks.put(task, callBack); } } public void cancelAllTaskBinder() { if (taskExecutor != null) { taskExecutor.cancle(); } } public boolean cancel(Object task) { Map<Object, ICallback<DATA>> callbacks = getCallbacks(); if (callbacks == null) { return false; } if (task.equals(realTask)) { if (!callbacks.isEmpty()) { if (callback != null) { callback.onPostExecute(realTask, Code.CANCEL, null, null); } callback = null; } else { cancelAllTaskBinder(); } return true; } else { Iterator<? extends Map.Entry<Object, ? extends ICallback<? extends BASE_DATA>>> iterator = callbacks.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry<Object, ? extends ICallback<? extends BASE_DATA>> data = iterator.next(); Object ct = data.getKey(); if (task.equals(ct)) { iterator.remove(); data.getValue().onPostExecute(ct, Code.CANCEL, null, null); return true; } } } return false; } public boolean isRunning() { if (taskExecutor != null) { return taskExecutor.isRunning(); } return false; } } public static <DATA> TaskExecutor<DATA> createExecutor(IDataSource<DATA> dataSource, boolean isExeRefresh, ICallback<DATA> callback) { return TaskExecutors.create(dataSource, isExeRefresh, callback); } public static <DATA> TaskExecutor<DATA> createExecutor(IAsyncDataSource<DATA> dataSource, boolean isExeRefresh, ICallback<DATA> callback) { return TaskExecutors.create(dataSource, isExeRefresh, callback); } public static <DATA> TaskExecutor<DATA> createExecutor(ITask<DATA> task, ICallback<DATA> callback) { return TaskExecutors.create(task, callback); } public static <DATA> TaskExecutor<DATA> createExecutor(IAsyncTask<DATA> task, ICallback<DATA> callback) { return TaskExecutors.create(task, callback); } }