优化Scheduler代码

pull/330/head
AriaLyy 8 years ago
parent 2fabf1a168
commit ad6ea4fac9
  1. 8
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  2. 2
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  3. 13
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  4. 3
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
  5. 23
      Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java
  6. 190
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  7. 171
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
  8. 153
      Aria/src/main/java/com/arialyy/aria/core/scheduler/UploadSchedulers.java
  9. 2
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java

@ -56,6 +56,8 @@ import org.xml.sax.SAXException;
private static final String DOWNLOAD = "_download";
private static final String UPLOAD = "_upload";
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;
private Map<String, IReceiver> mReceivers = new HashMap<>();
public static Context APP;
@ -247,6 +249,7 @@ import org.xml.sax.SAXException;
*/
private void initConfig() {
File xmlFile = new File(APP.getFilesDir().getPath() + Configuration.XML_FILE);
File tempDir = new File(APP.getFilesDir().getPath() + "/temp");
if (!xmlFile.exists()) {
loadConfig();
} else {
@ -261,6 +264,11 @@ import org.xml.sax.SAXException;
}
mDConfig = Configuration.DownloadConfig.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.
* 读取配置文件
*/
public class ConfigHelper extends DefaultHandler {
class ConfigHelper extends DefaultHandler {
private final String TAG = "ConfigHelper";
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) {
if (TextUtils.isEmpty(downloadName)) {
@ -138,6 +140,17 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
return this;
}
/**
* 设置文件名
*/
public DownloadTarget setFileName(@NonNull String fileName) {
if (TextUtils.isEmpty(fileName)) {
throw new IllegalArgumentException("文件名不能为null");
}
entity.setFileName(fileName);
return this;
}
private DownloadEntity getDownloadEntity() {
return entity;
}

@ -61,7 +61,6 @@ class DownloadUtil implements IDownloadUtil, Runnable {
private DownloadStateConstance CONSTANCE;
DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener) {
CheckUtil.checkTaskEntity(entity);
mDownloadEntity = entity.downloadEntity;
mContext = context.getApplicationContext();
mDownloadTaskEntity = entity;
@ -77,7 +76,7 @@ class DownloadUtil implements IDownloadUtil, Runnable {
mDownloadFile = new File(mDownloadTaskEntity.downloadEntity.getDownloadPath());
//读取已完成的线程数
mConfigFile = new File(
mContext.getFilesDir().getPath() + "/temp/" + mDownloadFile.getName() + ".properties");
mContext.getFilesDir().getPath() + AriaManager.DOWNLOAD_TEMP_DIR + mDownloadFile.getName() + ".properties");
try {
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
handleNewTask();

@ -114,7 +114,7 @@ final class SingleThreadTask implements Runnable {
if (mConfigEntity.isSupportBreakpoint) {
Log.i(TAG,
"任务【" + mConfigEntity.TEMP_FILE.getName() + "】线程【" + mConfigEntity.THREAD_ID + "】下载完毕");
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID, 1);
writeConfig(1);
mListener.onChildComplete(mConfigEntity.END_LOCATION);
CONSTANCE.COMPLETE_THREAD_NUM++;
if (CONSTANCE.isComplete()) {
@ -131,12 +131,11 @@ final class SingleThreadTask implements Runnable {
mListener.onComplete();
}
} catch (MalformedURLException e) {
failDownload(mConfigEntity, mChildCurrentLocation, "下载链接异常", e);
failDownload(mChildCurrentLocation, "下载链接异常", e);
} catch (IOException e) {
failDownload(mConfigEntity, mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】",
e);
failDownload(mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e);
} catch (Exception e) {
failDownload(mConfigEntity, mChildCurrentLocation, "获取流失败", e);
failDownload(mChildCurrentLocation, "获取流失败", e);
}
}
@ -152,8 +151,7 @@ final class SingleThreadTask implements Runnable {
+ mConfigEntity.THREAD_ID
+ "_stop, stop location ==> "
+ mChildCurrentLocation);
writeConfig(mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID,
mChildCurrentLocation);
writeConfig(mChildCurrentLocation);
if (CONSTANCE.isStop()) {
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
CONSTANCE.isDownloading = false;
@ -212,19 +210,17 @@ final class SingleThreadTask implements Runnable {
/**
* 下载失败
*/
private void failDownload(DownloadUtil.ConfigEntity dEntity, long currentLocation, String msg,
Exception ex) {
private void failDownload(long currentLocation, String msg, Exception ex) {
synchronized (LOCK) {
try {
CONSTANCE.FAIL_NUM++;
CONSTANCE.isDownloading = false;
CONSTANCE.isStop = true;
if (ex != null) {
Log.e(TAG, CommonUtil.getPrintException(ex));
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
}
if (mConfigEntity.isSupportBreakpoint) {
writeConfig(dEntity.TEMP_FILE.getName() + "_record_" + dEntity.THREAD_ID,
currentLocation);
writeConfig(currentLocation);
if (CONSTANCE.isFail()) {
Log.d(TAG, "++++++++++++++++ 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) {
String key = mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID;
File configFile = new File(mConfigFPath);
Properties pro = CommonUtil.loadConfig(configFile);
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;
import android.os.CountDownTimer;
import android.os.Message;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.download.DownloadEntity;
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.
* 任务下载器提供抽象的方法供具体的实现类操作
*/
public class DownloadSchedulers implements ISchedulers<DownloadTask> {
public class DownloadSchedulers
extends AbsSchedulers<DownloadTaskEntity, DownloadEntity, DownloadTask, DownloadTaskQueue> {
private static final String TAG = "DownloadSchedulers";
private static final Object LOCK = new Object();
private static volatile DownloadSchedulers INSTANCE = null;
/**
* 下载器任务监听
*/
private Map<String, IDownloadSchedulerListener<DownloadTask>> mSchedulerListeners =
new ConcurrentHashMap<>();
private DownloadTaskQueue mQueue;
private DownloadSchedulers() {
mQueue = DownloadTaskQueue.getInstance();
}
@ -57,156 +44,4 @@ public class DownloadSchedulers implements ISchedulers<DownloadTask> {
}
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;
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.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTask;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import com.arialyy.aria.core.upload.UploadTaskEntity;
/**
* 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 Object LOCK = new Object();
private static volatile UploadSchedulers INSTANCE = null;
private Map<String, ISchedulerListener<UploadTask>> mSchedulerListeners =
new ConcurrentHashMap<>();
private UploadTaskQueue mQueue;
private UploadSchedulers() {
mQueue = UploadTaskQueue.getInstance();
@ -53,141 +43,4 @@ public class UploadSchedulers implements ISchedulers<UploadTask> {
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) {
//if (db != null && db.isOpen()) db.close();
if (db != null && db.isOpen()) db.close();
}
private static SQLiteDatabase checkDb(SQLiteDatabase db) {

Loading…
Cancel
Save