优化Scheduler代码
This commit is contained in:
@ -56,6 +56,8 @@ import org.xml.sax.SAXException;
|
|||||||
private static final String DOWNLOAD = "_download";
|
private static final String DOWNLOAD = "_download";
|
||||||
private static final String UPLOAD = "_upload";
|
private static final String UPLOAD = "_upload";
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
|
public static final String DOWNLOAD_TEMP_DIR = "/Aria/temp/download/";
|
||||||
|
public static final String UPLOAD_TEMP_DIR = "/Aria/temp/upload/";
|
||||||
@SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
|
@SuppressLint("StaticFieldLeak") private static volatile AriaManager INSTANCE = null;
|
||||||
private Map<String, IReceiver> mReceivers = new HashMap<>();
|
private Map<String, IReceiver> mReceivers = new HashMap<>();
|
||||||
public static Context APP;
|
public static Context APP;
|
||||||
@ -247,6 +249,7 @@ import org.xml.sax.SAXException;
|
|||||||
*/
|
*/
|
||||||
private void initConfig() {
|
private void initConfig() {
|
||||||
File xmlFile = new File(APP.getFilesDir().getPath() + Configuration.XML_FILE);
|
File xmlFile = new File(APP.getFilesDir().getPath() + Configuration.XML_FILE);
|
||||||
|
File tempDir = new File(APP.getFilesDir().getPath() + "/temp");
|
||||||
if (!xmlFile.exists()) {
|
if (!xmlFile.exists()) {
|
||||||
loadConfig();
|
loadConfig();
|
||||||
} else {
|
} else {
|
||||||
@ -261,6 +264,11 @@ import org.xml.sax.SAXException;
|
|||||||
}
|
}
|
||||||
mDConfig = Configuration.DownloadConfig.getInstance();
|
mDConfig = Configuration.DownloadConfig.getInstance();
|
||||||
mUConfig = Configuration.UploadConfig.getInstance();
|
mUConfig = Configuration.UploadConfig.getInstance();
|
||||||
|
if (tempDir.exists()) {
|
||||||
|
File newDir = new File(APP.getFilesDir().getPath() + DOWNLOAD_TEMP_DIR);
|
||||||
|
newDir.mkdirs();
|
||||||
|
tempDir.renameTo(newDir);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -25,7 +25,7 @@ import org.xml.sax.helpers.DefaultHandler;
|
|||||||
* Created by lyy on 2017/5/22.
|
* Created by lyy on 2017/5/22.
|
||||||
* 读取配置文件
|
* 读取配置文件
|
||||||
*/
|
*/
|
||||||
public class ConfigHelper extends DefaultHandler {
|
class ConfigHelper extends DefaultHandler {
|
||||||
private final String TAG = "ConfigHelper";
|
private final String TAG = "ConfigHelper";
|
||||||
|
|
||||||
private boolean isDownloadConfig = false, isUploadConfig;
|
private boolean isDownloadConfig = false, isUploadConfig;
|
||||||
|
@ -129,6 +129,8 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置文件名
|
* 设置文件名
|
||||||
|
*
|
||||||
|
* @deprecated {@link #setFileName(String)}
|
||||||
*/
|
*/
|
||||||
@Deprecated public DownloadTarget setDownloadName(@NonNull String downloadName) {
|
@Deprecated public DownloadTarget setDownloadName(@NonNull String downloadName) {
|
||||||
if (TextUtils.isEmpty(downloadName)) {
|
if (TextUtils.isEmpty(downloadName)) {
|
||||||
@ -138,6 +140,17 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置文件名
|
||||||
|
*/
|
||||||
|
public DownloadTarget setFileName(@NonNull String fileName) {
|
||||||
|
if (TextUtils.isEmpty(fileName)) {
|
||||||
|
throw new IllegalArgumentException("文件名不能为null");
|
||||||
|
}
|
||||||
|
entity.setFileName(fileName);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
private DownloadEntity getDownloadEntity() {
|
private DownloadEntity getDownloadEntity() {
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
@ -61,7 +61,6 @@ class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
private DownloadStateConstance CONSTANCE;
|
private DownloadStateConstance CONSTANCE;
|
||||||
|
|
||||||
DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener) {
|
DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener) {
|
||||||
CheckUtil.checkTaskEntity(entity);
|
|
||||||
mDownloadEntity = entity.downloadEntity;
|
mDownloadEntity = entity.downloadEntity;
|
||||||
mContext = context.getApplicationContext();
|
mContext = context.getApplicationContext();
|
||||||
mDownloadTaskEntity = entity;
|
mDownloadTaskEntity = entity;
|
||||||
@ -77,7 +76,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
|
|||||||
mDownloadFile = new File(mDownloadTaskEntity.downloadEntity.getDownloadPath());
|
mDownloadFile = new File(mDownloadTaskEntity.downloadEntity.getDownloadPath());
|
||||||
//读取已完成的线程数
|
//读取已完成的线程数
|
||||||
mConfigFile = new File(
|
mConfigFile = new File(
|
||||||
mContext.getFilesDir().getPath() + "/temp/" + mDownloadFile.getName() + ".properties");
|
mContext.getFilesDir().getPath() + AriaManager.DOWNLOAD_TEMP_DIR + mDownloadFile.getName() + ".properties");
|
||||||
try {
|
try {
|
||||||
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
|
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
|
||||||
handleNewTask();
|
handleNewTask();
|
||||||
|
@ -114,7 +114,7 @@ final class SingleThreadTask implements Runnable {
|
|||||||
if (mConfigEntity.isSupportBreakpoint) {
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
Log.i(TAG,
|
Log.i(TAG,
|
||||||
"任务【" + mConfigEntity.TEMP_FILE.getName() + "】线程【" + mConfigEntity.THREAD_ID + "】下载完毕");
|
"任务【" + mConfigEntity.TEMP_FILE.getName() + "】线程【" + mConfigEntity.THREAD_ID + "】下载完毕");
|
||||||
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID, 1);
|
writeConfig(1);
|
||||||
mListener.onChildComplete(mConfigEntity.END_LOCATION);
|
mListener.onChildComplete(mConfigEntity.END_LOCATION);
|
||||||
CONSTANCE.COMPLETE_THREAD_NUM++;
|
CONSTANCE.COMPLETE_THREAD_NUM++;
|
||||||
if (CONSTANCE.isComplete()) {
|
if (CONSTANCE.isComplete()) {
|
||||||
@ -131,12 +131,11 @@ final class SingleThreadTask implements Runnable {
|
|||||||
mListener.onComplete();
|
mListener.onComplete();
|
||||||
}
|
}
|
||||||
} catch (MalformedURLException e) {
|
} catch (MalformedURLException e) {
|
||||||
failDownload(mConfigEntity, mChildCurrentLocation, "下载链接异常", e);
|
failDownload(mChildCurrentLocation, "下载链接异常", e);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
failDownload(mConfigEntity, mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】",
|
failDownload(mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e);
|
||||||
e);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
failDownload(mConfigEntity, mChildCurrentLocation, "获取流失败", e);
|
failDownload(mChildCurrentLocation, "获取流失败", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,8 +151,7 @@ final class SingleThreadTask implements Runnable {
|
|||||||
+ mConfigEntity.THREAD_ID
|
+ mConfigEntity.THREAD_ID
|
||||||
+ "_stop, stop location ==> "
|
+ "_stop, stop location ==> "
|
||||||
+ mChildCurrentLocation);
|
+ mChildCurrentLocation);
|
||||||
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID,
|
writeConfig(mChildCurrentLocation);
|
||||||
mChildCurrentLocation);
|
|
||||||
if (CONSTANCE.isStop()) {
|
if (CONSTANCE.isStop()) {
|
||||||
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
|
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
|
||||||
CONSTANCE.isDownloading = false;
|
CONSTANCE.isDownloading = false;
|
||||||
@ -212,19 +210,17 @@ final class SingleThreadTask implements Runnable {
|
|||||||
/**
|
/**
|
||||||
* 下载失败
|
* 下载失败
|
||||||
*/
|
*/
|
||||||
private void failDownload(DownloadUtil.ConfigEntity dEntity, long currentLocation, String msg,
|
private void failDownload(long currentLocation, String msg, Exception ex) {
|
||||||
Exception ex) {
|
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
try {
|
try {
|
||||||
CONSTANCE.FAIL_NUM++;
|
CONSTANCE.FAIL_NUM++;
|
||||||
CONSTANCE.isDownloading = false;
|
CONSTANCE.isDownloading = false;
|
||||||
CONSTANCE.isStop = true;
|
CONSTANCE.isStop = true;
|
||||||
if (ex != null) {
|
if (ex != null) {
|
||||||
Log.e(TAG, CommonUtil.getPrintException(ex));
|
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
|
||||||
}
|
}
|
||||||
if (mConfigEntity.isSupportBreakpoint) {
|
if (mConfigEntity.isSupportBreakpoint) {
|
||||||
writeConfig(dEntity.TEMP_FILE.getName() + "_record_" + dEntity.THREAD_ID,
|
writeConfig(currentLocation);
|
||||||
currentLocation);
|
|
||||||
if (CONSTANCE.isFail()) {
|
if (CONSTANCE.isFail()) {
|
||||||
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
|
Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++");
|
||||||
mListener.onFail();
|
mListener.onFail();
|
||||||
@ -242,8 +238,9 @@ final class SingleThreadTask implements Runnable {
|
|||||||
/**
|
/**
|
||||||
* 将记录写入到配置文件
|
* 将记录写入到配置文件
|
||||||
*/
|
*/
|
||||||
private void writeConfig(String key, long record) throws IOException {
|
private void writeConfig(long record) throws IOException {
|
||||||
if (record > 0) {
|
if (record > 0) {
|
||||||
|
String key = mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID;
|
||||||
File configFile = new File(mConfigFPath);
|
File configFile = new File(mConfigFPath);
|
||||||
Properties pro = CommonUtil.loadConfig(configFile);
|
Properties pro = CommonUtil.loadConfig(configFile);
|
||||||
pro.setProperty(key, String.valueOf(record));
|
pro.setProperty(key, String.valueOf(record));
|
||||||
|
@ -0,0 +1,190 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package com.arialyy.aria.core.scheduler;
|
||||||
|
|
||||||
|
import android.os.CountDownTimer;
|
||||||
|
import android.os.Message;
|
||||||
|
import android.util.Log;
|
||||||
|
import com.arialyy.aria.core.AriaManager;
|
||||||
|
import com.arialyy.aria.core.inf.AbsEntity;
|
||||||
|
import com.arialyy.aria.core.inf.AbsTaskEntity;
|
||||||
|
import com.arialyy.aria.core.inf.IEntity;
|
||||||
|
import com.arialyy.aria.core.inf.ITask;
|
||||||
|
import com.arialyy.aria.core.queue.ITaskQueue;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by AriaL on 2017/6/4.
|
||||||
|
*/
|
||||||
|
public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsEntity, TASK extends ITask<ENTITY>, QUEUE extends ITaskQueue<TASK, TASK_ENTITY, ENTITY>>
|
||||||
|
implements ISchedulers<TASK> {
|
||||||
|
private static final String TAG = "AbsSchedulers";
|
||||||
|
|
||||||
|
protected QUEUE mQueue;
|
||||||
|
|
||||||
|
private Map<String, IDownloadSchedulerListener<TASK>> mSchedulerListeners =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addSchedulerListener(String targetName, ISchedulerListener<TASK> schedulerListener) {
|
||||||
|
mSchedulerListeners.put(targetName, (IDownloadSchedulerListener<TASK>) schedulerListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void removeSchedulerListener(String targetName,
|
||||||
|
ISchedulerListener<TASK> schedulerListener) {
|
||||||
|
//该内存泄露解决方案:http://stackoverflow.com/questions/14585829/how-safe-is-to-delete-already-removed-concurrenthashmap-element
|
||||||
|
for (Iterator<Map.Entry<String, IDownloadSchedulerListener<TASK>>> iter =
|
||||||
|
mSchedulerListeners.entrySet().iterator(); iter.hasNext(); ) {
|
||||||
|
Map.Entry<String, IDownloadSchedulerListener<TASK>> entry = iter.next();
|
||||||
|
if (entry.getKey().equals(targetName)) iter.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public boolean handleMessage(Message msg) {
|
||||||
|
TASK task = (TASK) msg.obj;
|
||||||
|
if (task == null) {
|
||||||
|
Log.e(TAG, "请传入下载任务");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
callback(msg.what, task);
|
||||||
|
ENTITY entity = task.getEntity();
|
||||||
|
switch (msg.what) {
|
||||||
|
case STOP:
|
||||||
|
case CANCEL:
|
||||||
|
mQueue.removeTask(entity);
|
||||||
|
if (mQueue.executePoolSize() < AriaManager.getInstance(AriaManager.APP)
|
||||||
|
.getUploadConfig()
|
||||||
|
.getMaxTaskNum()) {
|
||||||
|
startNextTask();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case COMPLETE:
|
||||||
|
mQueue.removeTask(entity);
|
||||||
|
startNextTask();
|
||||||
|
break;
|
||||||
|
case FAIL:
|
||||||
|
handleFailTask(task);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 回调
|
||||||
|
*
|
||||||
|
* @param state 状态
|
||||||
|
*/
|
||||||
|
private void callback(int state, TASK task) {
|
||||||
|
if (mSchedulerListeners.size() > 0) {
|
||||||
|
Set<String> keys = mSchedulerListeners.keySet();
|
||||||
|
for (String key : keys) {
|
||||||
|
callback(state, task, mSchedulerListeners.get(key));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void callback(int state, TASK task, IDownloadSchedulerListener<TASK> listener) {
|
||||||
|
if (listener != null) {
|
||||||
|
if (task == null) {
|
||||||
|
Log.e(TAG, "TASK 为null,回调失败");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switch (state) {
|
||||||
|
case PRE:
|
||||||
|
listener.onPre(task);
|
||||||
|
break;
|
||||||
|
case POST_PRE:
|
||||||
|
listener.onTaskPre(task);
|
||||||
|
break;
|
||||||
|
case RUNNING:
|
||||||
|
listener.onTaskRunning(task);
|
||||||
|
break;
|
||||||
|
case START:
|
||||||
|
listener.onTaskStart(task);
|
||||||
|
break;
|
||||||
|
case STOP:
|
||||||
|
listener.onTaskStop(task);
|
||||||
|
break;
|
||||||
|
case RESUME:
|
||||||
|
listener.onTaskResume(task);
|
||||||
|
break;
|
||||||
|
case CANCEL:
|
||||||
|
listener.onTaskCancel(task);
|
||||||
|
break;
|
||||||
|
case COMPLETE:
|
||||||
|
listener.onTaskComplete(task);
|
||||||
|
break;
|
||||||
|
case FAIL:
|
||||||
|
listener.onTaskFail(task);
|
||||||
|
break;
|
||||||
|
case SUPPORT_BREAK_POINT:
|
||||||
|
listener.onNoSupportBreakPoint(task);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理下载任务下载失败的情形
|
||||||
|
*
|
||||||
|
* @param task 下载任务
|
||||||
|
*/
|
||||||
|
private void handleFailTask(final TASK task) {
|
||||||
|
final long interval =
|
||||||
|
AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryInterval();
|
||||||
|
final int reTryNum = AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryNum();
|
||||||
|
|
||||||
|
CountDownTimer timer = new CountDownTimer(interval, 1000) {
|
||||||
|
@Override public void onTick(long millisUntilFinished) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onFinish() {
|
||||||
|
ENTITY entity = task.getEntity();
|
||||||
|
if (entity.getFailNum() < reTryNum) {
|
||||||
|
TASK task = mQueue.getTask(entity);
|
||||||
|
mQueue.reTryStart(task);
|
||||||
|
try {
|
||||||
|
Thread.sleep(interval);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mQueue.removeTask(entity);
|
||||||
|
startNextTask();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动下一个任务,条件:任务停止,取消下载,任务完成
|
||||||
|
*/
|
||||||
|
private void startNextTask() {
|
||||||
|
TASK newTask = mQueue.getNextTask();
|
||||||
|
if (newTask == null) {
|
||||||
|
Log.w(TAG, "没有下一任务");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (newTask.getEntity().getState() == IEntity.STATE_WAIT) {
|
||||||
|
mQueue.startTask(newTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -16,35 +16,22 @@
|
|||||||
|
|
||||||
package com.arialyy.aria.core.scheduler;
|
package com.arialyy.aria.core.scheduler;
|
||||||
|
|
||||||
import android.os.CountDownTimer;
|
import com.arialyy.aria.core.download.DownloadTaskEntity;
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
import com.arialyy.aria.core.AriaManager;
|
|
||||||
import com.arialyy.aria.core.queue.DownloadTaskQueue;
|
import com.arialyy.aria.core.queue.DownloadTaskQueue;
|
||||||
import com.arialyy.aria.core.download.DownloadEntity;
|
import com.arialyy.aria.core.download.DownloadEntity;
|
||||||
import com.arialyy.aria.core.download.DownloadTask;
|
import com.arialyy.aria.core.download.DownloadTask;
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2016/8/16.
|
* Created by lyy on 2016/8/16.
|
||||||
* 任务下载器,提供抽象的方法供具体的实现类操作
|
* 任务下载器,提供抽象的方法供具体的实现类操作
|
||||||
*/
|
*/
|
||||||
public class DownloadSchedulers implements ISchedulers<DownloadTask> {
|
public class DownloadSchedulers
|
||||||
|
extends AbsSchedulers<DownloadTaskEntity, DownloadEntity, DownloadTask, DownloadTaskQueue> {
|
||||||
|
|
||||||
private static final String TAG = "DownloadSchedulers";
|
private static final String TAG = "DownloadSchedulers";
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
private static volatile DownloadSchedulers INSTANCE = null;
|
private static volatile DownloadSchedulers INSTANCE = null;
|
||||||
|
|
||||||
/**
|
|
||||||
* 下载器任务监听
|
|
||||||
*/
|
|
||||||
private Map<String, IDownloadSchedulerListener<DownloadTask>> mSchedulerListeners =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
private DownloadTaskQueue mQueue;
|
|
||||||
|
|
||||||
private DownloadSchedulers() {
|
private DownloadSchedulers() {
|
||||||
mQueue = DownloadTaskQueue.getInstance();
|
mQueue = DownloadTaskQueue.getInstance();
|
||||||
}
|
}
|
||||||
@ -57,156 +44,4 @@ public class DownloadSchedulers implements ISchedulers<DownloadTask> {
|
|||||||
}
|
}
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void addSchedulerListener(String targetName,
|
|
||||||
ISchedulerListener<DownloadTask> schedulerListener) {
|
|
||||||
mSchedulerListeners.put(targetName,
|
|
||||||
(IDownloadSchedulerListener<DownloadTask>) schedulerListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void removeSchedulerListener(String targetName,
|
|
||||||
ISchedulerListener<DownloadTask> schedulerListener) {
|
|
||||||
//该内存溢出解决方案:http://stackoverflow.com/questions/14585829/how-safe-is-to-delete-already-removed-concurrenthashmap-element
|
|
||||||
for (Iterator<Map.Entry<String, IDownloadSchedulerListener<DownloadTask>>> iter =
|
|
||||||
mSchedulerListeners.entrySet().iterator(); iter.hasNext(); ) {
|
|
||||||
Map.Entry<String, IDownloadSchedulerListener<DownloadTask>> entry = iter.next();
|
|
||||||
if (entry.getKey().equals(targetName)) iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean handleMessage(Message msg) {
|
|
||||||
DownloadTask task = (DownloadTask) msg.obj;
|
|
||||||
if (task == null) {
|
|
||||||
Log.e(TAG, "请传入下载任务");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
callback(msg.what, task);
|
|
||||||
DownloadEntity entity = task.getDownloadEntity();
|
|
||||||
switch (msg.what) {
|
|
||||||
case STOP:
|
|
||||||
case CANCEL:
|
|
||||||
mQueue.removeTask(entity);
|
|
||||||
if (mQueue.executePoolSize() < AriaManager.getInstance(AriaManager.APP)
|
|
||||||
.getUploadConfig()
|
|
||||||
.getMaxTaskNum()) {
|
|
||||||
startNextTask();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COMPLETE:
|
|
||||||
mQueue.removeTask(entity);
|
|
||||||
startNextTask();
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
handleFailTask(task);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回调
|
|
||||||
*
|
|
||||||
* @param state 状态
|
|
||||||
*/
|
|
||||||
private void callback(int state, DownloadTask task) {
|
|
||||||
if (mSchedulerListeners.size() > 0) {
|
|
||||||
//if (!TextUtils.isEmpty(task.getTargetName())) {
|
|
||||||
// callback(state, task, mSchedulerListeners.get(task.getTargetName()));
|
|
||||||
//}
|
|
||||||
Set<String> keys = mSchedulerListeners.keySet();
|
|
||||||
for (String key : keys) {
|
|
||||||
callback(state, task, mSchedulerListeners.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void callback(int state, DownloadTask task,
|
|
||||||
IDownloadSchedulerListener<DownloadTask> listener) {
|
|
||||||
if (listener != null) {
|
|
||||||
if (task == null) {
|
|
||||||
Log.e(TAG, "TASK 为null,回调失败");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (state) {
|
|
||||||
case PRE:
|
|
||||||
listener.onPre(task);
|
|
||||||
break;
|
|
||||||
case POST_PRE:
|
|
||||||
listener.onTaskPre(task);
|
|
||||||
break;
|
|
||||||
case RUNNING:
|
|
||||||
listener.onTaskRunning(task);
|
|
||||||
break;
|
|
||||||
case START:
|
|
||||||
listener.onTaskStart(task);
|
|
||||||
break;
|
|
||||||
case STOP:
|
|
||||||
listener.onTaskStop(task);
|
|
||||||
break;
|
|
||||||
case RESUME:
|
|
||||||
listener.onTaskResume(task);
|
|
||||||
break;
|
|
||||||
case CANCEL:
|
|
||||||
listener.onTaskCancel(task);
|
|
||||||
break;
|
|
||||||
case COMPLETE:
|
|
||||||
listener.onTaskComplete(task);
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
listener.onTaskFail(task);
|
|
||||||
break;
|
|
||||||
case SUPPORT_BREAK_POINT:
|
|
||||||
listener.onNoSupportBreakPoint(task);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理下载任务下载失败的情形
|
|
||||||
*
|
|
||||||
* @param task 下载任务
|
|
||||||
*/
|
|
||||||
private void handleFailTask(final DownloadTask task) {
|
|
||||||
final long interval =
|
|
||||||
AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryInterval();
|
|
||||||
final int reTryNum = AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryNum();
|
|
||||||
|
|
||||||
CountDownTimer timer = new CountDownTimer(interval, 1000) {
|
|
||||||
@Override public void onTick(long millisUntilFinished) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void onFinish() {
|
|
||||||
DownloadEntity entity = task.getDownloadEntity();
|
|
||||||
if (entity.getFailNum() < reTryNum) {
|
|
||||||
DownloadTask task = mQueue.getTask(entity);
|
|
||||||
mQueue.reTryStart(task);
|
|
||||||
try {
|
|
||||||
Thread.sleep(interval);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mQueue.removeTask(entity);
|
|
||||||
startNextTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 启动下一个任务,条件:任务停止,取消下载,任务完成
|
|
||||||
*/
|
|
||||||
private void startNextTask() {
|
|
||||||
DownloadTask newTask = mQueue.getNextTask();
|
|
||||||
if (newTask == null) {
|
|
||||||
Log.w(TAG, "没有下一任务");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (newTask.getDownloadEntity().getState() == DownloadEntity.STATE_WAIT) {
|
|
||||||
mQueue.startTask(newTask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -15,30 +15,20 @@
|
|||||||
*/
|
*/
|
||||||
package com.arialyy.aria.core.scheduler;
|
package com.arialyy.aria.core.scheduler;
|
||||||
|
|
||||||
import android.os.CountDownTimer;
|
|
||||||
import android.os.Message;
|
|
||||||
import android.util.Log;
|
|
||||||
import com.arialyy.aria.core.AriaManager;
|
|
||||||
import com.arialyy.aria.core.inf.IEntity;
|
|
||||||
import com.arialyy.aria.core.queue.UploadTaskQueue;
|
import com.arialyy.aria.core.queue.UploadTaskQueue;
|
||||||
import com.arialyy.aria.core.upload.UploadEntity;
|
import com.arialyy.aria.core.upload.UploadEntity;
|
||||||
import com.arialyy.aria.core.upload.UploadTask;
|
import com.arialyy.aria.core.upload.UploadTask;
|
||||||
import java.util.Iterator;
|
import com.arialyy.aria.core.upload.UploadTaskEntity;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Created by lyy on 2017/2/27.
|
* Created by lyy on 2017/2/27.
|
||||||
* 上传任务调度器
|
* 上传任务调度器
|
||||||
*/
|
*/
|
||||||
public class UploadSchedulers implements ISchedulers<UploadTask> {
|
public class UploadSchedulers
|
||||||
|
extends AbsSchedulers<UploadTaskEntity, UploadEntity, UploadTask, UploadTaskQueue> {
|
||||||
private static final String TAG = "UploadSchedulers";
|
private static final String TAG = "UploadSchedulers";
|
||||||
private static final Object LOCK = new Object();
|
private static final Object LOCK = new Object();
|
||||||
private static volatile UploadSchedulers INSTANCE = null;
|
private static volatile UploadSchedulers INSTANCE = null;
|
||||||
private Map<String, ISchedulerListener<UploadTask>> mSchedulerListeners =
|
|
||||||
new ConcurrentHashMap<>();
|
|
||||||
private UploadTaskQueue mQueue;
|
|
||||||
|
|
||||||
private UploadSchedulers() {
|
private UploadSchedulers() {
|
||||||
mQueue = UploadTaskQueue.getInstance();
|
mQueue = UploadTaskQueue.getInstance();
|
||||||
@ -53,141 +43,4 @@ public class UploadSchedulers implements ISchedulers<UploadTask> {
|
|||||||
|
|
||||||
return INSTANCE;
|
return INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override public void addSchedulerListener(String targetName,
|
|
||||||
ISchedulerListener<UploadTask> schedulerListener) {
|
|
||||||
mSchedulerListeners.put(targetName, schedulerListener);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void removeSchedulerListener(String targetName,
|
|
||||||
ISchedulerListener<UploadTask> schedulerListener) {
|
|
||||||
for (Iterator<Map.Entry<String, ISchedulerListener<UploadTask>>> iter =
|
|
||||||
mSchedulerListeners.entrySet().iterator(); iter.hasNext(); ) {
|
|
||||||
Map.Entry<String, ISchedulerListener<UploadTask>> entry = iter.next();
|
|
||||||
if (entry.getKey().equals(targetName)) iter.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void handleFailTask(final UploadTask task) {
|
|
||||||
final long interval =
|
|
||||||
AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryInterval();
|
|
||||||
final int reTryNum = AriaManager.getInstance(AriaManager.APP).getUploadConfig().getReTryNum();
|
|
||||||
CountDownTimer timer = new CountDownTimer(interval, 1000) {
|
|
||||||
@Override public void onTick(long millisUntilFinished) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public void onFinish() {
|
|
||||||
UploadEntity entity = task.getEntity();
|
|
||||||
if (entity.getFailNum() <= reTryNum) {
|
|
||||||
UploadTask task = mQueue.getTask(entity);
|
|
||||||
mQueue.reTryStart(task);
|
|
||||||
try {
|
|
||||||
Thread.sleep(interval);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
mQueue.removeTask(entity);
|
|
||||||
startNextTask();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
timer.start();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void startNextTask() {
|
|
||||||
UploadTask newTask = mQueue.getNextTask();
|
|
||||||
if (newTask == null) {
|
|
||||||
Log.w(TAG, "没有下一任务");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (newTask.getEntity().getState() == IEntity.STATE_WAIT) {
|
|
||||||
mQueue.startTask(newTask);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 回调
|
|
||||||
*
|
|
||||||
* @param state 状态
|
|
||||||
*/
|
|
||||||
private void callback(int state, UploadTask task) {
|
|
||||||
if (mSchedulerListeners.size() > 0) {
|
|
||||||
//if (!TextUtils.isEmpty(task.getTargetName())) {
|
|
||||||
// callback(state, task, mSchedulerListeners.get(task.getTargetName()));
|
|
||||||
//}
|
|
||||||
Set<String> keys = mSchedulerListeners.keySet();
|
|
||||||
for (String key : keys) {
|
|
||||||
callback(state, task, mSchedulerListeners.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void callback(int state, UploadTask task, ISchedulerListener<UploadTask> listener) {
|
|
||||||
if (listener != null) {
|
|
||||||
if (task == null) {
|
|
||||||
Log.e(TAG, "TASK 为null,回调失败");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switch (state) {
|
|
||||||
case PRE:
|
|
||||||
listener.onPre(task);
|
|
||||||
break;
|
|
||||||
case POST_PRE:
|
|
||||||
listener.onTaskPre(task);
|
|
||||||
break;
|
|
||||||
case RUNNING:
|
|
||||||
listener.onTaskRunning(task);
|
|
||||||
break;
|
|
||||||
case START:
|
|
||||||
listener.onTaskStart(task);
|
|
||||||
break;
|
|
||||||
case STOP:
|
|
||||||
listener.onTaskStop(task);
|
|
||||||
break;
|
|
||||||
case RESUME:
|
|
||||||
listener.onTaskResume(task);
|
|
||||||
break;
|
|
||||||
case CANCEL:
|
|
||||||
listener.onTaskCancel(task);
|
|
||||||
break;
|
|
||||||
case COMPLETE:
|
|
||||||
listener.onTaskComplete(task);
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
listener.onTaskFail(task);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override public boolean handleMessage(Message msg) {
|
|
||||||
UploadTask task = (UploadTask) msg.obj;
|
|
||||||
if (task == null) {
|
|
||||||
Log.e(TAG, "请传入上传任务");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
callback(msg.what, task);
|
|
||||||
UploadEntity entity = task.getEntity();
|
|
||||||
switch (msg.what) {
|
|
||||||
case STOP:
|
|
||||||
case CANCEL:
|
|
||||||
mQueue.removeTask(entity);
|
|
||||||
if (mQueue.executePoolSize() < AriaManager.getInstance(AriaManager.APP)
|
|
||||||
.getUploadConfig()
|
|
||||||
.getMaxTaskNum()) {
|
|
||||||
startNextTask();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case COMPLETE:
|
|
||||||
mQueue.removeTask(entity);
|
|
||||||
startNextTask();
|
|
||||||
break;
|
|
||||||
case FAIL:
|
|
||||||
handleFailTask(task);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -497,7 +497,7 @@ final class SqlHelper extends SQLiteOpenHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void close(SQLiteDatabase db) {
|
private static void close(SQLiteDatabase db) {
|
||||||
//if (db != null && db.isOpen()) db.close();
|
if (db != null && db.isOpen()) db.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static SQLiteDatabase checkDb(SQLiteDatabase db) {
|
private static SQLiteDatabase checkDb(SQLiteDatabase db) {
|
||||||
|
Reference in New Issue
Block a user