任务组功能实现

pull/330/head
AriaLyy 7 years ago
commit bf68a84cf0
  1. 9
      Aria/build.gradle
  2. 2
      Aria/jcenter.gradle
  3. 56
      Aria/src/main/java/com/arialyy/aria/core/Aria.java
  4. 23
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  5. 32
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  6. 31
      Aria/src/main/java/com/arialyy/aria/core/QueueMod.java
  7. 41
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
  8. 31
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java
  9. 4
      Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java
  10. 46
      Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
  11. 29
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
  12. 71
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
  13. 72
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
  14. 35
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java
  15. 61
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
  16. 12
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
  17. 67
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
  18. 13
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
  19. 16
      Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
  20. 22
      Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
  21. 17
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  22. 79
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  23. 4
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java
  24. 12
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
  25. 144
      Aria/src/main/java/com/arialyy/aria/core/download/DListener.java
  26. 116
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java
  27. 102
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  28. 241
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  29. 98
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  30. 31
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java
  31. 157
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  32. 112
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  33. 210
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  34. 20
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java
  35. 493
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
  36. 24
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java
  37. 3
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
  38. 403
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  39. 5
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java
  40. 420
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  41. 179
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java
  42. 42
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
  43. 36
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
  44. 104
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SimpleDownloadUtil.java
  45. 51
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
  46. 10
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java
  47. 65
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  48. 70
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  49. 26
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java
  50. 31
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
  51. 73
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java
  52. 106
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
  53. 44
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
  54. 27
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
  55. 212
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  56. 157
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
  57. 50
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java
  58. 21
      Aria/src/main/java/com/arialyy/aria/core/inf/IEntity.java
  59. 57
      Aria/src/main/java/com/arialyy/aria/core/inf/IEventListener.java
  60. 4
      Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java
  61. 86
      Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
  62. 21
      Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
  63. 108
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  64. 83
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java
  65. 84
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
  66. 50
      Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
  67. 32
      Aria/src/main/java/com/arialyy/aria/core/queue/TaskFactory.java
  68. 35
      Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
  69. 11
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseCachePool.java
  70. 75
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java
  71. 82
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java
  72. 43
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadSharePool.java
  73. 22
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
  74. 28
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/UploadExecutePool.java
  75. 43
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/UploadSharePool.java
  76. 58
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  77. 89
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DQueueMapping.java
  78. 74
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadGroupSchedulers.java
  79. 34
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
  80. 33
      Aria/src/main/java/com/arialyy/aria/core/scheduler/ISchedulers.java
  81. 9
      Aria/src/main/java/com/arialyy/aria/core/scheduler/UploadSchedulers.java
  82. 54
      Aria/src/main/java/com/arialyy/aria/core/upload/IUploadListener.java
  83. 78
      Aria/src/main/java/com/arialyy/aria/core/upload/ProxyHelper.java
  84. 21
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java
  85. 5
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadListener.java
  86. 81
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  87. 86
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
  88. 8
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java
  89. 10
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  90. 40
      Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java
  91. 23
      Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
  92. 32
      Aria/src/main/java/com/arialyy/aria/orm/NormalList.java
  93. 36
      Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java
  94. 38
      Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java
  95. 2
      Aria/src/main/java/com/arialyy/aria/orm/Primary.java
  96. 297
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  97. 27
      Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
  98. 171
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  99. 14
      Aria/src/main/res/layout/activity_aria_file_shange.xml
  100. 51
      Aria/src/main/res/layout/item_file.xml
  101. Some files were not shown because too many files have changed in this diff Show More

@ -2,7 +2,7 @@ apply plugin: 'com.android.library'
android { android {
compileSdkVersion 23 compileSdkVersion 23
buildToolsVersion '25.0.2' buildToolsVersion '25.0.3'
defaultConfig { defaultConfig {
minSdkVersion 9 minSdkVersion 9
@ -22,8 +22,7 @@ dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs') compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12' testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1' compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaCompiler') // compile project(':AriaCompiler')
// compile project(':AriaAnnotations') compile project(':AriaAnnotations') //gradle
} }
//apply from: 'bintray-release.gradle' apply from: 'bintray-release.gradle'
//apply from: 'jcenter.gradle'

@ -76,7 +76,7 @@ artifacts {
//################################# jcenter start ######################################### //################################# jcenter start #########################################
bintray { bintray {
// user = hasProperty("bintrayUser") ? getProperty("bintrayUser") : getProperty("BINTRAY_USER") // user = hasProperty("bintrayUser") ? getProperty("bintrayUser") : getProperty("BINTRAY_USER")
// key = hasProperty("bintrayKey") ? getProperty("bintrayKey") : getProperty("BINTRAY_KEY") // groupName = hasProperty("bintrayKey") ? getProperty("bintrayKey") : getProperty("BINTRAY_KEY")
user = BINTRAY_USER user = BINTRAY_USER
key = BINTRAY_KEY key = BINTRAY_KEY
configurations = ['archives'] configurations = ['archives']

@ -59,62 +59,6 @@ import com.arialyy.aria.core.upload.UploadTask;
* </pre> * </pre>
*/ */
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria { @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria {
/**
* 不支持断点
*/
public static final String ACTION_SUPPORT_BREAK_POINT = "ACTION_SUPPORT_BREAK_POINT";
/**
* 预处理完成
*/
public static final String ACTION_PRE = "ACTION_PRE";
/**
* 下载开始前事件
*/
public static final String ACTION_POST_PRE = "ACTION_POST_PRE";
/**
* 开始下载事件
*/
public static final String ACTION_START = "ACTION_START";
/**
* 恢复下载事件
*/
public static final String ACTION_RESUME = "ACTION_RESUME";
/**
* 正在下载事件
*/
public static final String ACTION_RUNNING = "ACTION_RUNNING";
/**
* 停止下载事件
*/
public static final String ACTION_STOP = "ACTION_STOP";
/**
* 取消下载事件
*/
public static final String ACTION_CANCEL = "ACTION_CANCEL";
/**
* 下载完成事件
*/
public static final String ACTION_COMPLETE = "ACTION_COMPLETE";
/**
* 下载失败事件
*/
public static final String ACTION_FAIL = "ACTION_FAIL";
/**
* 下载实体
*/
public static final String DOWNLOAD_ENTITY = "DOWNLOAD_ENTITY";
/**
* 上传实体
*/
public static final String UPLOAD_ENTITY = "UPLOAD_ENTITY";
/**
* 位置
*/
public static final String CURRENT_LOCATION = "CURRENT_LOCATION";
/**
* 速度
*/
public static final String CURRENT_SPEED = "CURRENT_SPEED";
private Aria() { private Aria() {
} }

@ -29,14 +29,13 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import com.arialyy.aria.core.download.DownloadReceiver; import com.arialyy.aria.core.download.DownloadReceiver;
import com.arialyy.aria.core.inf.ICmd; import com.arialyy.aria.core.command.ICmd;
import com.arialyy.aria.core.inf.IReceiver; import com.arialyy.aria.core.inf.IReceiver;
import com.arialyy.aria.core.upload.UploadReceiver; import com.arialyy.aria.core.upload.UploadReceiver;
import com.arialyy.aria.orm.DbUtil; import com.arialyy.aria.orm.DbUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator; import java.util.Iterator;
@ -86,6 +85,26 @@ import org.xml.sax.SAXException;
return mReceivers; return mReceivers;
} }
/**
* 设置上传任务的执行队列类型
*
* @param mod {@link com.arialyy.aria.core.QueueMod}
*/
public AriaManager setUploadQueueMod(QueueMod mod) {
mUConfig.setQueueMod(mod.tag);
return this;
}
/**
* 设置下载任务的执行队列类型
*
* @param mod {@link com.arialyy.aria.core.QueueMod}
*/
public AriaManager setDownloadQueueMod(QueueMod mod) {
mDConfig.setQueueMod(mod.tag);
return this;
}
/** /**
* 如果需要在代码中修改下载配置请使用以下方法 * 如果需要在代码中修改下载配置请使用以下方法
* <pre> * <pre>

@ -54,9 +54,6 @@ class ConfigHelper extends DefaultHandler {
case "threadNum": case "threadNum":
loadThreadNum(value); loadThreadNum(value);
break; break;
case "openBroadcast":
loadBroadcast(value);
break;
case "maxTaskNum": case "maxTaskNum":
loadMaxQueue(value); loadMaxQueue(value);
break; break;
@ -86,8 +83,25 @@ class ConfigHelper extends DefaultHandler {
case "maxSpeed": case "maxSpeed":
loadMaxSpeed(value); loadMaxSpeed(value);
break; break;
case "queueMod":
loadQueueMod(value);
break;
}
} }
} }
private void loadQueueMod(String value) {
String mod = "now";
if (!TextUtils.isEmpty(value) && (value.equalsIgnoreCase("now") || value.equalsIgnoreCase(
"wait"))) {
mod = value;
}
if (isDownloadConfig) {
mDownloadConfig.queueMod = mod;
}
if (isUploadConfig) {
mUploadConfig.queueMod = mod;
}
} }
private void loadMaxSpeed(String value) { private void loadMaxSpeed(String value) {
@ -95,7 +109,7 @@ class ConfigHelper extends DefaultHandler {
if (!TextUtils.isEmpty(value)) { if (!TextUtils.isEmpty(value)) {
maxSpeed = Double.parseDouble(value); maxSpeed = Double.parseDouble(value);
} }
if (isDownloadConfig){ if (isDownloadConfig) {
mDownloadConfig.msxSpeed = maxSpeed; mDownloadConfig.msxSpeed = maxSpeed;
} }
} }
@ -207,16 +221,6 @@ class ConfigHelper extends DefaultHandler {
} }
} }
private void loadBroadcast(String value) {
boolean open = Boolean.parseBoolean(value);
if (isDownloadConfig) {
mDownloadConfig.isOpenBreadCast = open;
}
if (isUploadConfig) {
mUploadConfig.isOpenBreadCast = open;
}
}
private void loadThreadNum(String value) { private void loadThreadNum(String value) {
int num = 3; int num = 3;
if (!TextUtils.isEmpty(value)) { if (!TextUtils.isEmpty(value)) {

@ -0,0 +1,31 @@
package com.arialyy.aria.core;
/**
* Created by Aria.Lao on 2017/6/21.
* 执行队列类型
*/
public enum QueueMod {
/**
* 等待模式
* 如果执行队列已经满了再对其它任务TASK_A使用start命令执行任务时
* 1TASK_A添加到缓存队列中当执行队列中的任务完成时系统会将自动执行缓存队列中的TASK_A
* 2如果再次对TASK_A使用start命令TASK_A将会立刻执行
*/
WAIT("wait"),
/**
* 立刻执行模式
* 如果执行队列已经满了再次使用start命令执行任务时该任务会添加到执行队列队尾而原来执行队列的队首任务会停止
*/
NOW("now");
String tag;
public String getTag() {
return tag;
}
QueueMod(String tag) {
this.tag = tag;
}
}

@ -16,43 +16,20 @@
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.ITaskQueue; import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.inf.ICmd;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
/** /**
* Created by lyy on 2016/8/22. * Created by AriaL on 2017/6/29.
* 下载命令
*/ */
public abstract class AbsCmd<T extends AbsTaskEntity> implements ICmd { public abstract class AbsCmd<T extends AbsTaskEntity> implements ICmd{
ITaskQueue mQueue; protected ITaskQueue mQueue;
T mEntity; protected T mTaskEntity;
String TAG; protected String TAG;
String mTargetName; protected String mTargetName;
/** /**
* 能否执行命令 * 是否是下载任务的命令
* {@code true} 下载任务的命令{@code false} 上传任务的命令
*/ */
boolean canExeCmd = true; protected boolean isDownloadCmd = true;
/**
* @param targetName 产生任务的对象名
*/
AbsCmd(String targetName, T entity) {
canExeCmd = CheckUtil.checkCmdEntity(entity,
!(this instanceof CancelCmd) || !(this instanceof StopCmd));
mTargetName = targetName;
mEntity = entity;
TAG = CommonUtil.getClassName(this);
if (entity instanceof DownloadTaskEntity) {
mQueue = DownloadTaskQueue.getInstance();
} else if (entity instanceof UploadTaskEntity) {
mQueue = UploadTaskQueue.getInstance();
}
}
} }

@ -0,0 +1,31 @@
/*
* 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.command;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* Created by AriaL on 2017/6/29.
* 抽象命令工厂
*/
public abstract class AbsCmdFactory<CMD extends AbsCmd> {
/**
* @param target 创建任务的对象
* @param entity 下载实体
*/
public abstract <T extends AbsTaskEntity> CMD createCmd(String target, T entity, int type);
}

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.command;
/** /**
* Created by lyy on 2017/2/9. * Created by lyy on 2017/2/9.
@ -23,5 +23,5 @@ public interface ICmd {
/** /**
* 执行命令 * 执行命令
*/ */
public abstract void executeCmd(); void executeCmd();
} }

@ -0,0 +1,46 @@
/*
* 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.command.group;
import com.arialyy.aria.core.command.AbsCmd;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by AriaL on 2017/6/29.
* 任务组命令
*/
abstract class AbsGroupCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
/**
* @param targetName 创建任务的对象名
*/
AbsGroupCmd(String targetName, T entity) {
mTargetName = targetName;
mTaskEntity = entity;
TAG = CommonUtil.getClassName(this);
if (entity instanceof DownloadGroupTaskEntity) {
mQueue = DownloadGroupTaskQueue.getInstance();
isDownloadCmd = true;
}
}
}

@ -13,34 +13,23 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.command.group;
package com.arialyy.aria.core.command;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
/** /**
* Created by lyy on 2016/8/22. * Created by AriaL on 2017/6/29.
* 开始命令 * 删除任务组
*/ */
class StartCmd<T extends AbsTaskEntity> extends AbsCmd<T> { class GroupCancelCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T> {
/**
StartCmd(String targetName, T entity) { * @param targetName 创建任务的对象名
*/
GroupCancelCmd(String targetName, T entity) {
super(targetName, entity); super(targetName, entity);
} }
@Override public void executeCmd() { @Override public void executeCmd() {
if (!canExeCmd) return;
ITask task = mQueue.getTask(mEntity.getEntity());
if (task == null) {
task = mQueue.createTask(mTargetName, mEntity);
}
if (task != null) {
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
mQueue.startTask(task);
}
} }
} }

@ -0,0 +1,71 @@
/*
* 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.command.group;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.AbsCmdFactory;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* Created by AriaL on 2017/6/29.
*/
class GroupCmdFactory extends AbsCmdFactory<AbsGroupCmd> {
/**
* 启动任务
*/
public static final int TASK_START = 0xa1;
/**
* 停止任务
*/
public static final int TASK_STOP = 0xa2;
/**
* 取消任务
*/
public static final int TASK_CANCEL = 0xa3;
private static volatile GroupCmdFactory INSTANCE = null;
private GroupCmdFactory() {
}
public static GroupCmdFactory getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new GroupCmdFactory();
}
}
return INSTANCE;
}
/**
* @param target 创建任务的对象
* @param entity 下载实体
* @param type 命令类型{@link #TASK_START}{@link #TASK_CANCEL}{@link #TASK_STOP}
*/
public <T extends AbsTaskEntity> AbsGroupCmd<T> createCmd(String target, T entity, int type) {
switch (type) {
case TASK_START:
return new GroupStartCmd<>(target, entity);
case TASK_STOP:
return new GroupStopCmd<>(target, entity);
case TASK_CANCEL:
return new GroupCancelCmd<>(target, entity);
default:
return null;
}
}
}

@ -0,0 +1,72 @@
/*
* 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.command.group;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.QueueMod;
import com.arialyy.aria.core.inf.AbsGroupTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
/**
* Created by AriaL on 2017/6/29.
* 任务组开始命令该命令负责开始下载或恢复下载的操作
*/
class GroupStartCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T> {
/**
* @param targetName 创建任务的对象名
*/
GroupStartCmd(String targetName, T entity) {
super(targetName, entity);
}
@Override public void executeCmd() {
String mod;
int maxTaskNum;
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
if (isDownloadCmd) {
mod = manager.getDownloadConfig().getQueueMod();
maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
} else {
mod = manager.getUploadConfig().getQueueMod();
maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
}
AbsGroupTask task = (AbsGroupTask) mQueue.getTask(mTaskEntity.getEntity());
if (task == null) {
task = (AbsGroupTask) mQueue.createTask(mTargetName, mTaskEntity);
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
// 任务不存在时,根据配置不同,对任务执行操作
if (mod.equals(QueueMod.NOW.getTag())) {
mQueue.startTask(task);
} else if (mod.equals(QueueMod.WAIT.getTag())) {
if (mQueue.getCurrentExePoolNum() < maxTaskNum) {
mQueue.startTask(task);
}
}
} else {
// 任务不存在时,根据配置不同,对任务执行操作
if (!task.isRunning()
&& mod.equals(QueueMod.WAIT.getTag())
&& task.getState() == IEntity.STATE_WAIT) {
mQueue.startTask(task);
}
}
}
}

@ -0,0 +1,35 @@
/*
* 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.command.group;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* Created by AriaL on 2017/6/29.
* 停止任务组的命令
*/
class GroupStopCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T>{
/**
* @param targetName 创建任务的对象名
*/
GroupStopCmd(String targetName, T entity) {
super(targetName, entity);
}
@Override public void executeCmd() {
}
}

@ -0,0 +1,61 @@
/*
* 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.command.normal;
import com.arialyy.aria.core.command.AbsCmd;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by lyy on 2016/8/22.
* 下载命令
*/
public abstract class AbsNormalCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
/**
* 能否执行命令
*/
boolean canExeCmd = true;
/**
* @param targetName 产生任务的对象名
*/
AbsNormalCmd(String targetName, T entity) {
//canExeCmd = CheckUtil.checkCmdEntity(entity,
// !(this instanceof CancelCmd) || !(this instanceof StopCmd));
mTargetName = targetName;
mTaskEntity = entity;
TAG = CommonUtil.getClassName(this);
if (entity instanceof DownloadTaskEntity) {
mQueue = DownloadTaskQueue.getInstance();
isDownloadCmd = true;
} else if (entity instanceof UploadTaskEntity) {
mQueue = UploadTaskQueue.getInstance();
isDownloadCmd = false;
} else if (entity instanceof DownloadGroupTaskEntity) {
mQueue = DownloadGroupTaskQueue.getInstance();
isDownloadCmd = true;
}
}
}

@ -14,18 +14,18 @@
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command.normal;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
/** /**
* Created by lyy on 2016/8/22. * Created by lyy on 2016/8/22.
* 添加任务的命令 * 添加任务的命令
*/ */
class AddCmd<T extends AbsTaskEntity> extends AbsCmd<T> { class AddCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
AddCmd(String targetName, T entity) { AddCmd(String targetName, T entity) {
super(targetName, entity); super(targetName, entity);
@ -33,10 +33,10 @@ class AddCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
@Override public void executeCmd() { @Override public void executeCmd() {
if (!canExeCmd) return; if (!canExeCmd) return;
ITask task = mQueue.getTask(mEntity.getEntity()); AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
if (task == null) { if (task == null) {
mEntity.getEntity().setState(IEntity.STATE_WAIT); mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
mQueue.createTask(mTargetName, mEntity); mQueue.createTask(mTargetName, mTaskEntity);
} else { } else {
Log.w(TAG, "添加命令执行失败,【该任务已经存在】"); Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
} }

@ -0,0 +1,67 @@
/*
* 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.command.normal;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.util.List;
/**
* Created by AriaL on 2017/6/27.
* 删除所有任务并且删除所有回掉
*/
final class CancelAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
/**
* @param targetName 产生任务的对象名
*/
CancelAllCmd(String targetName, T entity) {
super(targetName, entity);
}
@Override public void executeCmd() {
mQueue.removeAllTask();
if (mTaskEntity instanceof DownloadTaskEntity) {
handleDownloadRemove();
} else {
handleUploadRemove();
}
}
/**
* 处理上传的删除
*/
private void handleUploadRemove() {
List<UploadTaskEntity> allEntity = DbEntity.findAllData(UploadTaskEntity.class);
for (UploadTaskEntity entity : allEntity) {
CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, entity);
}
}
/**
* 处理下载的删除
*/
private void handleDownloadRemove() {
List<DownloadTaskEntity> allEntity = DbEntity.findAllData(DownloadTaskEntity.class);
for (DownloadTaskEntity entity : allEntity) {
CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, entity);
}
}
}

@ -14,32 +14,33 @@
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command.normal;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
/** /**
* Created by lyy on 2016/9/20. * Created by lyy on 2016/9/20.
* 取消命令 * 取消命令
*/ */
class CancelCmd<T extends AbsTaskEntity> extends AbsCmd<T> { class CancelCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
CancelCmd(String targetName, T entity) { CancelCmd(String targetName, T entity) {
super(targetName, entity); super(targetName, entity);
} }
@Override public void executeCmd() { @Override public void executeCmd() {
if (!canExeCmd) return; if (!canExeCmd) return;
ITask task = mQueue.getTask(mEntity.getEntity()); AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
if (task == null) { if (task == null) {
task = mQueue.createTask(mTargetName, mEntity); task = mQueue.createTask(mTargetName, mTaskEntity);
} }
if (task != null) { if (task != null) {
if (!TextUtils.isEmpty(mTargetName)) { if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName); task.setTargetName(mTargetName);
} }
mQueue.cancelTask(task); mQueue.removeTask(task);
} }
} }
} }

@ -13,11 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command.normal;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
/** /**
* Created by lyy on 2017/6/2. * Created by lyy on 2017/6/2.
@ -28,8 +30,10 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效 * 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行 * 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务 * 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*
* 目前只只支持单下载任务的最高优先级任务
*/ */
final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsCmd<T> { final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
/** /**
* @param targetName 产生任务的对象名 * @param targetName 产生任务的对象名
*/ */
@ -39,15 +43,15 @@ final class HighestPriorityCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
@Override public void executeCmd() { @Override public void executeCmd() {
if (!canExeCmd) return; if (!canExeCmd) return;
ITask task = mQueue.getTask(mEntity.getEntity()); DownloadTask task = (DownloadTask) mQueue.getTask(mTaskEntity.getEntity());
if (task == null) { if (task == null) {
task = mQueue.createTask(mTargetName, mEntity); task = (DownloadTask) mQueue.createTask(mTargetName, mTaskEntity);
} }
if (task != null) { if (task != null) {
if (!TextUtils.isEmpty(mTargetName)) { if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName); task.setTargetName(mTargetName);
} }
mQueue.setTaskHighestPriority(task); ((DownloadTaskQueue) mQueue).setTaskHighestPriority(task);
} }
} }
} }

@ -14,16 +14,17 @@
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command.normal;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.AbsCmdFactory;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
/** /**
* Created by Lyy on 2016/9/23. * Created by Lyy on 2016/9/23.
* 命令工厂 * 命令工厂
*/ */
public class CmdFactory { public class NormalCmdFactory extends AbsCmdFactory<AbsNormalCmd> {
/** /**
* 创建任务 * 创建任务
*/ */
@ -56,17 +57,20 @@ public class CmdFactory {
* 恢复所有停止的任务 * 恢复所有停止的任务
*/ */
public static final int TASK_RESUME_ALL = 0x130; public static final int TASK_RESUME_ALL = 0x130;
/**
* 删除所有任务
*/
public static final int TASK_CANCEL_ALL = 0x131;
private static volatile NormalCmdFactory INSTANCE = null;
private static volatile CmdFactory INSTANCE = null; private NormalCmdFactory() {
private CmdFactory() {
} }
public static CmdFactory getInstance() { public static NormalCmdFactory getInstance() {
if (INSTANCE == null) { if (INSTANCE == null) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
INSTANCE = new CmdFactory(); INSTANCE = new NormalCmdFactory();
} }
} }
return INSTANCE; return INSTANCE;
@ -78,7 +82,7 @@ public class CmdFactory {
* @param type 命令类型{@link #TASK_CREATE}{@link #TASK_START}{@link #TASK_CANCEL}{@link * @param type 命令类型{@link #TASK_CREATE}{@link #TASK_START}{@link #TASK_CANCEL}{@link
* #TASK_STOP}{@link #TASK_HIGHEST_PRIORITY}{@link #TASK_STOP_ALL}{@link #TASK_RESUME_ALL} * #TASK_STOP}{@link #TASK_HIGHEST_PRIORITY}{@link #TASK_STOP_ALL}{@link #TASK_RESUME_ALL}
*/ */
public <T extends AbsTaskEntity> AbsCmd<T> createCmd(String target, T entity, int type) { public <T extends AbsTaskEntity> AbsNormalCmd<T> createCmd(String target, T entity, int type) {
switch (type) { switch (type) {
case TASK_CREATE: case TASK_CREATE:
return new AddCmd<>(target, entity); return new AddCmd<>(target, entity);
@ -95,6 +99,8 @@ public class CmdFactory {
return new StopAllCmd<>(target, entity); return new StopAllCmd<>(target, entity);
case TASK_RESUME_ALL: case TASK_RESUME_ALL:
return new ResumeAllCmd<>(target, entity); return new ResumeAllCmd<>(target, entity);
case TASK_CANCEL_ALL:
return new CancelAllCmd<>(target, entity);
default: default:
return null; return null;
} }

@ -1,11 +1,11 @@
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command.normal;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import java.util.List; import java.util.List;
@ -15,7 +15,7 @@ import java.util.List;
* 1.如果执行队列没有满则开始下载任务直到执行队列满 * 1.如果执行队列没有满则开始下载任务直到执行队列满
* 2.如果队列执行队列已经满了则将所有任务添加到等待队列中 * 2.如果队列执行队列已经满了则将所有任务添加到等待队列中
*/ */
final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsCmd<T> { final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
/** /**
* @param targetName 产生任务的对象名 * @param targetName 产生任务的对象名
*/ */
@ -27,9 +27,9 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
List<DownloadEntity> allEntity = List<DownloadEntity> allEntity =
DbEntity.findDatas(DownloadEntity.class, "state=?", IEntity.STATE_STOP + ""); DbEntity.findDatas(DownloadEntity.class, "state=?", IEntity.STATE_STOP + "");
for (DownloadEntity entity : allEntity) { for (DownloadEntity entity : allEntity) {
int exeNum = mQueue.getExeTaskNum(); int exeNum = mQueue.getCurrentExePoolNum();
if (exeNum == 0 || exeNum < mQueue.getMaxTaskNum()) { if (exeNum == 0 || exeNum < mQueue.getMaxTaskNum()) {
ITask task = createTask(entity); AbsTask task = createTask(entity);
mQueue.startTask(task); mQueue.startTask(task);
} else { } else {
entity.setState(IEntity.STATE_WAIT); entity.setState(IEntity.STATE_WAIT);
@ -38,10 +38,11 @@ final class ResumeAllCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
} }
} }
private ITask createTask(DownloadEntity entity) { private AbsTask createTask(DownloadEntity entity) {
ITask task = mQueue.getTask(entity); AbsTask task = mQueue.getTask(entity);
if (task == null) { if (task == null) {
DownloadTaskEntity taskEntity = new DownloadTaskEntity(entity); DownloadTaskEntity taskEntity = new DownloadTaskEntity();
taskEntity.entity = entity;
task = mQueue.createTask(mTargetName, taskEntity); task = mQueue.createTask(mTargetName, taskEntity);
} else { } else {
Log.w(TAG, "添加命令执行失败,【该任务已经存在】"); Log.w(TAG, "添加命令执行失败,【该任务已经存在】");

@ -0,0 +1,79 @@
/*
* 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.command.normal;
import android.text.TextUtils;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.QueueMod;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.core.scheduler.DQueueMapping;
import com.arialyy.aria.orm.Primary;
/**
* Created by lyy on 2016/8/22.
* 开始命令
* 队列模型{@link QueueMod#NOW}{@link QueueMod#WAIT}
*/
class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
StartCmd(String targetName, T entity) {
super(targetName, entity);
}
@Override public void executeCmd() {
if (!canExeCmd) return;
String mod;
int maxTaskNum;
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
if (isDownloadCmd) {
mod = manager.getDownloadConfig().getQueueMod();
maxTaskNum = manager.getDownloadConfig().getMaxTaskNum();
} else {
mod = manager.getUploadConfig().getQueueMod();
maxTaskNum = manager.getUploadConfig().getMaxTaskNum();
}
AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
if (task == null) {
task = mQueue.createTask(mTargetName, mTaskEntity);
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
// 任务不存在时,根据配置不同,对任务执行操作
if (mod.equals(QueueMod.NOW.getTag())) {
mQueue.startTask(task);
} else if (mod.equals(QueueMod.WAIT.getTag())) {
if (mQueue.getCurrentExePoolNum() < maxTaskNum
|| task.getState() == IEntity.STATE_STOP
|| task.getState() == IEntity.STATE_COMPLETE) {
mQueue.startTask(task);
}
}
} else {
// 任务不存在时,根据配置不同,对任务执行操作
if (!task.isRunning()) {
mQueue.startTask(task);
}
}
}
}

@ -1,4 +1,4 @@
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command.normal;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
@ -6,7 +6,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
* Created by AriaL on 2017/6/13. * Created by AriaL on 2017/6/13.
* 停止所有任务的命令并清空所有等待队列 * 停止所有任务的命令并清空所有等待队列
*/ */
final class StopAllCmd<T extends AbsTaskEntity> extends AbsCmd<T> { final class StopAllCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
/** /**
* @param targetName 产生任务的对象名 * @param targetName 产生任务的对象名
*/ */

@ -14,19 +14,19 @@
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.command; package com.arialyy.aria.core.command.normal;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
/** /**
* Created by lyy on 2016/9/20. * Created by lyy on 2016/9/20.
* 停止命令 * 停止命令
*/ */
class StopCmd<T extends AbsTaskEntity> extends AbsCmd<T> { class StopCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
StopCmd(String targetName, T entity) { StopCmd(String targetName, T entity) {
super(targetName, entity); super(targetName, entity);
@ -34,10 +34,10 @@ class StopCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
@Override public void executeCmd() { @Override public void executeCmd() {
if (!canExeCmd) return; if (!canExeCmd) return;
ITask task = mQueue.getTask(mEntity.getEntity()); AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
if (task == null) { if (task == null) {
if (mEntity.getEntity().getState() == IEntity.STATE_RUNNING) { if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
task = mQueue.createTask(mTargetName, mEntity); task = mQueue.createTask(mTargetName, mTaskEntity);
mQueue.stopTask(task); mQueue.stopTask(task);
} else { } else {
Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】"); Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】");

@ -0,0 +1,144 @@
/*
* 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.download;
import android.os.Handler;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.downloader.DownloadListener;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.CommonUtil;
import java.lang.ref.WeakReference;
/**
* 下载监听类
*/
class DListener<ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>>
extends DownloadListener {
private WeakReference<Handler> outHandler;
private long lastLen = 0; //上一次发送长度
private boolean isFirst = true;
private ENTITY entity;
private TASK task;
private boolean isConvertSpeed = false;
boolean isWait = false;
DListener(TASK task, Handler outHandler) {
this.outHandler = new WeakReference<>(outHandler);
this.task = new WeakReference<>(task).get();
this.entity = this.task.getEntity();
final AriaManager manager = AriaManager.getInstance(AriaManager.APP);
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
}
@Override public void onPre() {
saveData(IEntity.STATE_PRE, -1);
sendInState2Target(ISchedulers.PRE);
}
@Override public void onPostPre(long fileSize) {
entity.setFileSize(fileSize);
entity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
saveData(IEntity.STATE_POST_PRE, -1);
sendInState2Target(ISchedulers.POST_PRE);
}
@Override public void onStart(long startLocation) {
saveData(IEntity.STATE_RUNNING, startLocation);
sendInState2Target(ISchedulers.START);
}
@Override public void onResume(long resumeLocation) {
saveData(IEntity.STATE_RUNNING, resumeLocation);
sendInState2Target(ISchedulers.RESUME);
}
@Override public void onProgress(long currentLocation) {
entity.setCurrentProgress(currentLocation);
long speed = currentLocation - lastLen;
if (isFirst) {
speed = 0;
isFirst = false;
}
handleSpeed(speed);
sendInState2Target(ISchedulers.RUNNING);
lastLen = currentLocation;
}
@Override public void onStop(long stopLocation) {
saveData(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
sendInState2Target(ISchedulers.STOP);
}
@Override public void onCancel() {
saveData(IEntity.STATE_CANCEL, -1);
handleSpeed(0);
sendInState2Target(ISchedulers.CANCEL);
}
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
handleSpeed(0);
sendInState2Target(ISchedulers.COMPLETE);
}
@Override public void onFail() {
entity.setFailNum(entity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, -1);
handleSpeed(0);
sendInState2Target(ISchedulers.FAIL);
}
private void handleSpeed(long speed) {
if (isConvertSpeed) {
entity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
} else {
entity.setSpeed(speed);
}
}
/**
* 将任务状态发送给下载器
*
* @param state {@link ISchedulers#START}
*/
private void sendInState2Target(int state) {
if (outHandler.get() != null) {
outHandler.get().obtainMessage(state, task).sendToTarget();
}
}
private void saveData(int state, long location) {
if (state == IEntity.STATE_CANCEL) {
entity.deleteData();
} else if (state == IEntity.STATE_COMPLETE) {
entity.setState(state);
entity.setComplete(true);
entity.setCompleteTime(System.currentTimeMillis());
entity.setCurrentProgress(entity.getFileSize());
entity.update();
} else {
entity.setState(state);
if (location != -1) {
entity.setCurrentProgress(location);
}
entity.update();
}
}
}

@ -18,25 +18,107 @@ package com.arialyy.aria.core.download;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.Primary;
/** /**
* Created by lyy on 2015/12/25. * Created by lyy on 2015/12/25.
* 下载实体 * 下载实体
* 注意CREATOR要进行@Ignore注解
* 并且需要Parcelable时需要手动填写rowID;
*/ */
public class DownloadEntity extends AbsEntity implements Parcelable { public class DownloadEntity extends AbsNormalEntity implements Parcelable {
private String downloadUrl = ""; //下载路径 private String downloadUrl = ""; //下载路径
private String downloadPath = ""; //保存路径 @Primary private String downloadPath = ""; //保存路径
private boolean isDownloadComplete = false; //是否下载完成
private boolean isRedirect = false; //是否重定向 private boolean isRedirect = false; //是否重定向
private String redirectUrl = ""; //重定向链接 private String redirectUrl = ""; //重定向链接
/**
* 所属任务组
*/
private String groupName = "";
/**
* 通过{@link AbsTaskEntity#md5Key}从服务器的返回信息中获取的文件md5信息如果服务器没有返回则不会设置该信息
* 如果你已经设置了该任务的MD5信息Aria也不会从服务器返回的信息中获取该信息
*/
private String md5Code = "";
/**
* 通过{@link AbsTaskEntity#dispositionKey}从服务器的返回信息中获取的文件描述信息
*/
private String disposition = "";
/**
* 从disposition获取到的文件名如果可以获取到则会赋值到这个字段
*/
private String serverFileName = "";
@Override public String getKey() {
return downloadUrl;
}
public DownloadEntity() { public DownloadEntity() {
} }
@Override public String toString() {
return "DownloadEntity{"
+ "downloadUrl='"
+ downloadUrl
+ '\''
+ ", downloadPath='"
+ downloadPath
+ '\''
+ ", isRedirect="
+ isRedirect
+ ", redirectUrl='"
+ redirectUrl
+ '\''
+ ", groupName='"
+ groupName
+ '\''
+ ", md5Code='"
+ md5Code
+ '\''
+ ", disposition='"
+ disposition
+ '\''
+ ", serverFileName='"
+ serverFileName
+ '\''
+ '}';
}
public String getMd5Code() {
return md5Code;
}
public void setMd5Code(String md5Code) {
this.md5Code = md5Code;
}
public String getDisposition() {
return disposition;
}
public void setDisposition(String disposition) {
this.disposition = disposition;
}
public String getServerFileName() {
return serverFileName;
}
public void setServerFileName(String serverFileName) {
this.serverFileName = serverFileName;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public String getDownloadUrl() { public String getDownloadUrl() {
return downloadUrl; return downloadUrl;
@ -56,14 +138,6 @@ public class DownloadEntity extends AbsEntity implements Parcelable {
return this; return this;
} }
public boolean isDownloadComplete() {
return isDownloadComplete;
}
public void setDownloadComplete(boolean downloadComplete) {
isDownloadComplete = downloadComplete;
}
@Override public DownloadEntity clone() throws CloneNotSupportedException { @Override public DownloadEntity clone() throws CloneNotSupportedException {
return (DownloadEntity) super.clone(); return (DownloadEntity) super.clone();
} }
@ -92,21 +166,27 @@ public class DownloadEntity extends AbsEntity implements Parcelable {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
dest.writeString(this.downloadUrl); dest.writeString(this.downloadUrl);
dest.writeString(this.downloadPath); dest.writeString(this.downloadPath);
dest.writeByte(this.isDownloadComplete ? (byte) 1 : (byte) 0);
dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0); dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0);
dest.writeString(this.redirectUrl); dest.writeString(this.redirectUrl);
dest.writeString(this.groupName);
dest.writeString(this.md5Code);
dest.writeString(this.disposition);
dest.writeString(this.serverFileName);
} }
protected DownloadEntity(Parcel in) { protected DownloadEntity(Parcel in) {
super(in); super(in);
this.downloadUrl = in.readString(); this.downloadUrl = in.readString();
this.downloadPath = in.readString(); this.downloadPath = in.readString();
this.isDownloadComplete = in.readByte() != 0;
this.isRedirect = in.readByte() != 0; this.isRedirect = in.readByte() != 0;
this.redirectUrl = in.readString(); this.redirectUrl = in.readString();
this.groupName = in.readString();
this.md5Code = in.readString();
this.disposition = in.readString();
this.serverFileName = in.readString();
} }
@Ignore public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() { public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() {
@Override public DownloadEntity createFromParcel(Parcel source) { @Override public DownloadEntity createFromParcel(Parcel source) {
return new DownloadEntity(source); return new DownloadEntity(source);
} }

@ -0,0 +1,102 @@
/*
* 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.download;
import android.os.Parcel;
import com.arialyy.aria.core.inf.AbsGroupEntity;
import com.arialyy.aria.orm.NormalList;
import com.arialyy.aria.orm.OneToMany;
import java.util.ArrayList;
import java.util.List;
/**
* Created by AriaL on 2017/6/29.
* 下载任务组实体
*/
public class DownloadGroupEntity extends AbsGroupEntity {
@OneToMany(table = DownloadEntity.class, key = "groupName") private List<DownloadEntity> subtask =
new ArrayList<>();
/**
* 子任务链接组
*/
@NormalList(clazz = String.class) private List<String> urls = new ArrayList<>();
/**
* 任务组下载文件的文件夹地址
*
* @see DownloadGroupTarget#setDownloadDirPath(String)
*/
private String dirPath = "";
public List<DownloadEntity> getSubTask() {
return subtask;
}
void setSubTasks(List<DownloadEntity> subTasks) {
this.subtask = subTasks;
}
public String getDirPath() {
return dirPath;
}
public void setDirPath(String dirPath) {
this.dirPath = dirPath;
}
public List<String> getUrls() {
return urls;
}
void setUrls(List<String> urls) {
this.urls = urls;
}
void setGroupName(String key) {
this.groupName = key;
}
public DownloadGroupEntity() {
}
@Override public int describeContents() {
return 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeTypedList(this.subtask);
dest.writeString(this.dirPath);
}
protected DownloadGroupEntity(Parcel in) {
super(in);
this.subtask = in.createTypedArrayList(DownloadEntity.CREATOR);
this.dirPath = in.readString();
}
public static final Creator<DownloadGroupEntity> CREATOR = new Creator<DownloadGroupEntity>() {
@Override public DownloadGroupEntity createFromParcel(Parcel source) {
return new DownloadGroupEntity(source);
}
@Override public DownloadGroupEntity[] newArray(int size) {
return new DownloadGroupEntity[size];
}
};
}

@ -0,0 +1,241 @@
/*
* 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.download;
import android.text.TextUtils;
import com.arialyy.aria.core.inf.AbsGroupTarget;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.DbUtil;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Created by AriaL on 2017/6/29.
*/
public class DownloadGroupTarget
extends AbsGroupTarget<DownloadGroupTarget, DownloadGroupEntity, DownloadGroupTaskEntity> {
private List<String> mUrls = new ArrayList<>();
private final String TAG = "DownloadGroupTarget";
/**
* 子任务文件名
*/
private List<String> mSubTaskFileName = new ArrayList<>();
private String mGroupName;
/**
* 是否已经设置了文件路径
*/
private boolean isSetDirPathed = false;
DownloadGroupTarget(DownloadGroupEntity groupEntity, String targetName) {
this.mTargetName = targetName;
if (groupEntity.getUrls() != null && !groupEntity.getUrls().isEmpty()) {
this.mUrls.addAll(groupEntity.getUrls());
}
init(groupEntity.getGroupName());
}
DownloadGroupTarget(List<String> urls, String targetName) {
this.mTargetName = targetName;
this.mUrls = urls;
init(CommonUtil.getMd5Code(urls));
}
private void init(String key) {
mGroupName = key;
mTaskEntity = DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", key);
if (mTaskEntity == null) {
mTaskEntity = new DownloadGroupTaskEntity();
mTaskEntity.key = key;
mTaskEntity.entity = getDownloadGroupEntity();
mTaskEntity.insert();
}
if (mTaskEntity.entity == null) {
mTaskEntity.entity = getDownloadGroupEntity();
}
mEntity = mTaskEntity.entity;
}
/**
* 查询任务组实体如果数据库不存在该实体则新创建一个新的任务组实体
*/
private DownloadGroupEntity getDownloadGroupEntity() {
DownloadGroupEntity entity =
DbEntity.findFirst(DownloadGroupEntity.class, "groupName=?", mGroupName);
if (entity == null) {
entity = new DownloadGroupEntity();
entity.setGroupName(mGroupName);
entity.setUrls(mUrls);
entity.insert();
}
return entity;
}
/**
* 设置任务组别名
*/
public DownloadGroupTarget setGroupAlias(String alias) {
if (TextUtils.isEmpty(alias)) return this;
mEntity.setAlias(alias);
mEntity.update();
return this;
}
/**
* 如果你是使用{@link DownloadReceiver#load(DownloadGroupEntity)}进行下载操作那么你需要设置任务组的下载地址
*/
public DownloadGroupTarget setGroupUrl(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
mUrls.clear();
mUrls.addAll(urls);
mEntity.setGroupName(CommonUtil.getMd5Code(urls));
mEntity.update();
return this;
}
/**
* 设置任务组的文件夹路径在Aria中任务组的所有子任务都会下载到以任务组组名的文件夹中
* groupDirPath = "/mnt/sdcard/download/group_test"
* <pre>
* {@code
* + mnt
* + sdcard
* + download
* + group_test
* - task1.apk
* - task2.apk
* - task3.apk
* ....
*
* }
* </pre>
*
* @param groupDirPath 任务组保存文件夹路径
*/
public DownloadGroupTarget setDownloadDirPath(String groupDirPath) {
if (TextUtils.isEmpty(groupDirPath)) {
throw new NullPointerException("任务组文件夹保存路径不能为null");
}
isSetDirPathed = true;
if (mEntity.getDirPath().equals(groupDirPath)) return this;
File file = new File(groupDirPath);
if (file.exists() && file.isFile()) {
throw new IllegalArgumentException("路径不能为文件");
}
if (!file.exists()) {
file.mkdirs();
}
mEntity.setDirPath(groupDirPath);
if (!TextUtils.isEmpty(mEntity.getDirPath())) {
reChangeDirPath(groupDirPath);
} else {
mEntity.setSubTasks(createSubTask());
}
mEntity.update();
return this;
}
/**
* 改变任务组文件夹路径修改文件夹路径会将子任务所有路径更换
*
* @param newDirPath 新的文件夹路径
*/
private void reChangeDirPath(String newDirPath) {
List<DownloadEntity> subTask = mEntity.getSubTask();
if (subTask != null && !subTask.isEmpty()) {
for (DownloadEntity entity : subTask) {
String oldPath = entity.getDownloadPath();
String newPath = newDirPath + "/" + entity.getFileName();
File file = new File(oldPath);
file.renameTo(new File(newPath));
DbEntity.exeSql("UPDATE DownloadEntity SET downloadPath='"
+ newPath
+ "' WHERE downloadPath='"
+ oldPath
+ "'");
DbEntity.exeSql(
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
}
} else {
mEntity.setSubTasks(createSubTask());
}
}
/**
* 设置子任务文件名该方法必须在{@link #setDownloadDirPath(String)}之后调用否则不生效
*/
public DownloadGroupTarget setSubTaskFileName(List<String> subTaskFileName) {
if (subTaskFileName == null || subTaskFileName.isEmpty()) return this;
mSubTaskFileName.addAll(subTaskFileName);
if (mUrls.size() != subTaskFileName.size()) {
throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致");
}
if (isSetDirPathed) {
List<DownloadEntity> entities = mEntity.getSubTask();
int i = 0;
for (DownloadEntity entity : entities) {
String newName = mSubTaskFileName.get(i);
updateSubFileName(entity, newName);
i++;
}
}
return this;
}
/**
* 更新子任务文件名
*/
private void updateSubFileName(DownloadEntity entity, String newName) {
if (!newName.equals(entity.getFileName())) {
String oldPath = mEntity.getDirPath() + "/" + entity.getFileName();
String newPath = mEntity.getDirPath() + "/" + newName;
File file = new File(oldPath);
if (file.exists()) {
file.renameTo(new File(newPath));
}
DbEntity.exeSql(
"UPDATE DownloadTaskEntity SET key='" + newPath + "' WHERE key='" + oldPath + "'");
entity.setDownloadPath(newPath);
entity.setFileName(newName);
entity.update();
}
}
/**
* 创建子任务
*/
private List<DownloadEntity> createSubTask() {
List<DownloadEntity> list = new ArrayList<>();
for (int i = 0, len = mUrls.size(); i < len; i++) {
DownloadEntity entity = new DownloadEntity();
entity.setDownloadUrl(mUrls.get(i));
String fileName = mSubTaskFileName.isEmpty() ? createFileName(entity.getDownloadUrl())
: mSubTaskFileName.get(i);
entity.setDownloadPath(mEntity.getDirPath() + "/" + fileName);
entity.setGroupName(mGroupName);
entity.setGroupChild(true);
entity.setFileName(fileName);
entity.insert();
list.add(entity);
}
return list;
}
}

@ -0,0 +1,98 @@
/*
* 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.download;
import android.os.Handler;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.downloader.DownloadGroupUtil;
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
import com.arialyy.aria.core.inf.AbsGroupTask;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.CheckUtil;
/**
* Created by AriaL on 2017/6/27.
* 任务组任务
*/
public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity, DownloadGroupEntity> {
private final String TAG = "DownloadGroupTask";
private DListener<DownloadGroupEntity, DownloadGroupTask> mListener;
private IDownloadUtil mUtil;
private DownloadGroupTask(DownloadGroupTaskEntity taskEntity, Handler outHandler) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mOutHandler = outHandler;
mContext = AriaManager.APP;
mListener = new DListener<>(this, mOutHandler);
mUtil = new DownloadGroupUtil(mListener, mTaskEntity);
}
@Override public boolean isRunning() {
return mUtil.isDownloading();
}
@Override public void start() {
mUtil.startDownload();
}
@Override public void stop() {
if (!mUtil.isDownloading()) {
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
}
}
mUtil.stopDownload();
}
@Override public void cancel() {
if (!mUtil.isDownloading()) {
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
}
}
mUtil.cancelDownload();
}
public static class Builder {
DownloadGroupTaskEntity taskEntity;
Handler outHandler;
String targetName;
public Builder(String targetName, DownloadGroupTaskEntity taskEntity) {
CheckUtil.checkTaskEntity(taskEntity);
this.targetName = targetName;
this.taskEntity = taskEntity;
}
/**
* 设置自定义Handler处理下载状态时间
*
* @param schedulers {@link ISchedulers}
*/
public DownloadGroupTask.Builder setOutHandler(ISchedulers schedulers) {
this.outHandler = new Handler(schedulers);
return this;
}
public DownloadGroupTask build() {
DownloadGroupTask task = new DownloadGroupTask(taskEntity, outHandler);
task.setTargetName(targetName);
taskEntity.save();
return task;
}
}
}

@ -0,0 +1,31 @@
/*
* 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.download;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.OneToOne;
/**
* Created by AriaL on 2017/7/1.
*/
public class DownloadGroupTaskEntity extends AbsTaskEntity<DownloadGroupEntity> {
@OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity;
@Override public DownloadGroupEntity getEntity() {
return entity;
}
}

@ -17,12 +17,14 @@ package com.arialyy.aria.core.download;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.ICmd; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.IReceiver; import com.arialyy.aria.core.inf.IReceiver;
import com.arialyy.aria.core.command.CmdFactory; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.command.AbsCmd; import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
import com.arialyy.aria.core.scheduler.DownloadSchedulers; import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulerListener; import com.arialyy.aria.core.scheduler.ISchedulerListener;
import com.arialyy.aria.core.upload.ProxyHelper;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
@ -34,10 +36,8 @@ import java.util.Set;
* Created by lyy on 2016/12/5. * Created by lyy on 2016/12/5.
* 下载功能接收器 * 下载功能接收器
*/ */
public class DownloadReceiver implements IReceiver<DownloadEntity> { public class DownloadReceiver extends AbsReceiver {
private static final String TAG = "DownloadReceiver"; private final String TAG = "DownloadReceiver";
public String targetName;
public Object obj;
public ISchedulerListener<DownloadTask> listener; public ISchedulerListener<DownloadTask> listener;
/** /**
@ -51,43 +51,51 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
} }
/** /**
* {@link #load(String)}请使用该方法 * 使用下载实体执行下载操作
*/ */
@Deprecated public DownloadTarget load(DownloadEntity entity) { public DownloadTarget load(DownloadEntity entity) {
return new DownloadTarget(entity, targetName); return new DownloadTarget(entity, targetName);
} }
/** /**
* 读取下载链接 * 加载下载地址
*/ */
public DownloadTarget load(@NonNull String downloadUrl) { public DownloadTarget load(@NonNull String downloadUrl) {
CheckUtil.checkDownloadUrl(downloadUrl); CheckUtil.checkDownloadUrl(downloadUrl);
DownloadEntity entity = return new DownloadTarget(downloadUrl, targetName);
DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", downloadUrl);
if (entity == null) {
entity = new DownloadEntity();
} }
entity.setDownloadUrl(downloadUrl);
return new DownloadTarget(entity, targetName); /**
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/
public DownloadGroupTarget load(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
return new DownloadGroupTarget(urls, targetName);
} }
/** /**
* 添加调度器回调 * 使用任务组实体执行任务组的实体执行任务组的下载操作
* *
* @see #register() * @param groupEntity 如果加载的任务实体没有子项的下载地址
* 那么你需要使用{@link DownloadGroupTarget#setGroupUrl(List)}设置子项的下载地址
*/ */
@Deprecated public DownloadReceiver addSchedulerListener( public DownloadGroupTarget load(DownloadGroupEntity groupEntity) {
ISchedulerListener<DownloadTask> listener) { return new DownloadGroupTarget(groupEntity, targetName);
this.listener = listener;
DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener);
return this;
} }
/** /**
* 将当前类注册到Aria * 将当前类注册到Aria
*/ */
public DownloadReceiver register() { public DownloadReceiver register() {
String className = obj.getClass().getName();
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
if (dCounter != null && dCounter.contains(className)) {
DownloadSchedulers.getInstance().register(obj); DownloadSchedulers.getInstance().register(obj);
}
if (dgCounter != null && dgCounter.contains(className)) {
DownloadGroupSchedulers.getInstance().register(obj);
}
return this; return this;
} }
@ -95,8 +103,28 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
* 取消注册 * 取消注册
*/ */
@Override public void unRegister() { @Override public void unRegister() {
String className = obj.getClass().getName();
Set<String> dCounter = ProxyHelper.getInstance().downloadCounter;
Set<String> dgCounter = ProxyHelper.getInstance().downloadGroupCounter;
if (dCounter != null && dCounter.contains(className)) {
DownloadSchedulers.getInstance().unRegister(obj); DownloadSchedulers.getInstance().unRegister(obj);
} }
if (dgCounter != null && dgCounter.contains(className)) {
DownloadGroupSchedulers.getInstance().unRegister(obj);
}
}
/**
* 添加调度器回调
*
* @see #register()
*/
@Deprecated public DownloadReceiver addSchedulerListener(
ISchedulerListener<DownloadTask> listener) {
this.listener = listener;
DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener);
return this;
}
/** /**
* 移除回调 * 移除回调
@ -119,27 +147,74 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
*/ */
public DownloadEntity getDownloadEntity(String downloadUrl) { public DownloadEntity getDownloadEntity(String downloadUrl) {
CheckUtil.checkDownloadUrl(downloadUrl); CheckUtil.checkDownloadUrl(downloadUrl);
return DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", downloadUrl); return DbEntity.findFirst(DownloadEntity.class, "downloadUrl=? and isGroupChild='false'",
downloadUrl);
}
/**
* 通过下载链接获取保存在数据库的下载任务实体
*/
public DownloadTaskEntity getDownloadTask(String downloadUrl) {
CheckUtil.checkDownloadUrl(downloadUrl);
return DbEntity.findFirst(DownloadTaskEntity.class, "groupName=? and isGroupTask='false'",
downloadUrl);
}
/**
* 通过下载链接获取保存在数据库的下载任务组实体
*/
public DownloadGroupTaskEntity getDownloadGroupTask(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
String hashCode = CommonUtil.getMd5Code(urls);
return DbEntity.findFirst(DownloadGroupTaskEntity.class, "key=?", hashCode);
} }
/** /**
* 下载任务是否存在 * 下载任务是否存在
*/ */
@Override public boolean taskExists(String downloadUrl) { @Override public boolean taskExists(String downloadUrl) {
return DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", downloadUrl) != null; return DownloadEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl) != null;
}
/**
* 获取普通下载任务列表
*/
@Override public List<DownloadEntity> getSimpleTaskList() {
return DownloadEntity.findDatas(DownloadEntity.class, "isGroupChild=? and downloadPath!=''",
"false");
} }
@Override public List<DownloadEntity> getTaskList() { /**
return DownloadEntity.findAllData(DownloadEntity.class); * 获取任务组列表
*/
public List<DownloadGroupEntity> getGroupTaskList() {
return DownloadEntity.findAllData(DownloadGroupEntity.class);
}
/**
* 获取普通任务和任务组的任务列表
*/
public List<AbsEntity> getTotleTaskList() {
List<AbsEntity> list = new ArrayList<>();
List<DownloadEntity> simpleTask = getSimpleTaskList();
List<DownloadGroupEntity> groupTask = getGroupTaskList();
if (simpleTask != null && !simpleTask.isEmpty()) {
list.addAll(simpleTask);
}
if (groupTask != null && !groupTask.isEmpty()) {
list.addAll(groupTask);
}
return list;
} }
/** /**
* 停止所有正在下载的任务并清空等待队列 * 停止所有正在下载的任务并清空等待队列
*/ */
@Override public void stopAllTask() { @Override public void stopAllTask() {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP); AriaManager.getInstance(AriaManager.APP)
ariaManager.setCmd(CmdFactory.getInstance() .setCmd(NormalCmdFactory.getInstance()
.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_STOP_ALL)).exe(); .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL))
.exe();
} }
/** /**
@ -148,23 +223,23 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
* 2.如果队列执行队列已经满了则将所有任务添加到等待队列中 * 2.如果队列执行队列已经满了则将所有任务添加到等待队列中
*/ */
public void resumeAllTask() { public void resumeAllTask() {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP); AriaManager.getInstance(AriaManager.APP)
ariaManager.setCmd(CmdFactory.getInstance() .setCmd(NormalCmdFactory.getInstance()
.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_RESUME_ALL)).exe(); .createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_RESUME_ALL))
.exe();
} }
/** /**
* 删除所有任务 * 删除所有任务
*
* @param removeFile {@code true} 删除已经下载完成的任务不仅删除下载记录还会删除已经下载完成的文件{@code false}
* 如果文件已经下载完成只删除下载记录
*/ */
@Override public void removeAllTask() { @Override public void removeAllTask(boolean removeFile) {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP); final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
List<DownloadEntity> allEntity = DbEntity.findAllData(DownloadEntity.class); ariaManager.setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(),
List<AbsCmd> cancelCmds = new ArrayList<>(); NormalCmdFactory.TASK_CANCEL_ALL)).exe();
for (DownloadEntity entity : allEntity) {
cancelCmds.add(
CommonUtil.createCmd(targetName, new DownloadTaskEntity(entity), CmdFactory.TASK_CANCEL));
}
ariaManager.setCmds(cancelCmds).exe();
Set<String> keys = ariaManager.getReceiver().keySet(); Set<String> keys = ariaManager.getReceiver().keySet();
for (String key : keys) { for (String key : keys) {
IReceiver receiver = ariaManager.getReceiver().get(key); IReceiver receiver = ariaManager.getReceiver().get(key);

@ -17,31 +17,60 @@ package com.arialyy.aria.core.download;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import com.arialyy.aria.core.inf.AbsNormalTarget;
import com.arialyy.aria.core.RequestEnum; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.core.queue.DownloadTaskQueue;
import com.arialyy.aria.orm.DbEntity;
import java.io.File; import java.io.File;
import java.util.Map;
/** /**
* Created by lyy on 2016/12/5. * Created by lyy on 2016/12/5.
* https://github.com/AriaLyy/Aria * https://github.com/AriaLyy/Aria
*/ */
public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity> { public class DownloadTarget
extends AbsNormalTarget<DownloadTarget, DownloadEntity, DownloadTaskEntity> {
DownloadTarget(DownloadEntity entity, String targetName) { DownloadTarget(DownloadEntity entity, String targetName) {
this.entity = entity; this(entity.getDownloadUrl(), targetName);
this.targetName = targetName;
taskEntity = new DownloadTaskEntity(entity);
} }
@Override public void pause() { DownloadTarget(String url, String targetName) {
super.pause(); mTargetName = targetName;
DownloadEntity entity = getEntity(url);
mTaskEntity = DbEntity.findFirst(DownloadTaskEntity.class, "key=? and isGroupTask='false'",
entity.getDownloadPath());
if (mTaskEntity == null) {
mTaskEntity = new DownloadTaskEntity();
mTaskEntity.key = entity.getDownloadPath();
mTaskEntity.entity = entity;
mTaskEntity.save();
}
if (mTaskEntity.entity == null) {
mTaskEntity.entity = entity;
}
mEntity = entity;
} }
@Override public void resume() { /**
super.resume(); * 如果任务存在但是下载实体不存在则通过下载地址获取下载实体
*
* @param downloadUrl 下载地址
*/
private DownloadEntity getEntity(String downloadUrl) {
DownloadEntity entity =
DownloadEntity.findFirst(DownloadEntity.class, "downloadUrl=? and isGroupChild='false'",
downloadUrl);
if (entity == null) {
entity = new DownloadEntity();
entity.setDownloadUrl(downloadUrl);
entity.setGroupChild(false);
entity.save();
}
File file = new File(entity.getDownloadPath());
if (!file.exists()) {
entity.setState(IEntity.STATE_WAIT);
}
return entity;
} }
/** /**
@ -65,53 +94,11 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
return this; return this;
} }
@Override public int getPercent() {
if (entity == null) {
Log.e("DownloadTarget", "下载管理器中没有该任务");
return 0;
}
if (entity.getFileSize() != 0) {
return (int) (entity.getCurrentProgress() * 100 / entity.getFileSize());
}
return super.getPercent();
}
/**
* 给url请求添加头部
*
* @param key 头部key
* @param header 头部value
*/
public DownloadTarget addHeader(@NonNull String key, @NonNull String header) {
super._addHeader(key, header);
return this;
}
/**
* 给url请求添加头部
*
* @param headers key为http头部的keyValue为http头对应的配置
*/
public DownloadTarget addHeaders(Map<String, String> headers) {
super._addHeaders(headers);
return this;
}
/** /**
* 下载任务是否存在 * 下载任务是否存在
*/ */
@Override public boolean taskExists() { @Override public boolean taskExists() {
return DownloadTaskQueue.getInstance().getTask(entity.getDownloadUrl()) != null; return DownloadTaskQueue.getInstance().getTask(mEntity.getDownloadUrl()) != null;
}
/**
* 设置请求类型
*
* @param requestEnum {@link RequestEnum}
*/
public DownloadTarget setRequestMode(RequestEnum requestEnum) {
super._setRequestMode(requestEnum);
return this;
} }
/** /**
@ -122,8 +109,11 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
throw new IllegalArgumentException("文件保持路径不能为null"); throw new IllegalArgumentException("文件保持路径不能为null");
} }
File file = new File(downloadPath); File file = new File(downloadPath);
entity.setDownloadPath(downloadPath); mEntity.setDownloadPath(downloadPath);
entity.setFileName(file.getName()); mEntity.setFileName(file.getName());
mTaskEntity.key = downloadPath;
mEntity.update();
mTaskEntity.update();
return this; return this;
} }
@ -136,7 +126,7 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
if (TextUtils.isEmpty(downloadName)) { if (TextUtils.isEmpty(downloadName)) {
throw new IllegalArgumentException("文件名不能为null"); throw new IllegalArgumentException("文件名不能为null");
} }
entity.setFileName(downloadName); mEntity.setFileName(downloadName);
return this; return this;
} }
@ -147,19 +137,19 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
if (TextUtils.isEmpty(fileName)) { if (TextUtils.isEmpty(fileName)) {
throw new IllegalArgumentException("文件名不能为null"); throw new IllegalArgumentException("文件名不能为null");
} }
entity.setFileName(fileName); mEntity.setFileName(fileName);
return this; return this;
} }
private DownloadEntity getDownloadEntity() { private DownloadEntity getDownloadEntity() {
return entity; return mEntity;
} }
/** /**
* 是否在下载 * 是否在下载
*/ */
public boolean isDownloading() { public boolean isDownloading() {
DownloadTask task = DownloadTaskQueue.getInstance().getTask(entity); DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity);
return task != null && task.isRunning(); return task != null && task.isRunning();
} }
} }

@ -16,39 +16,31 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import android.content.Context;
import android.content.Intent;
import android.os.Handler; import android.os.Handler;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask; import com.arialyy.aria.core.download.downloader.SimpleDownloadUtil;
import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.File; import java.io.File;
import java.lang.ref.WeakReference;
/** /**
* Created by lyy on 2016/8/11. * Created by lyy on 2016/8/11.
* 下载任务类 * 下载任务类
*/ */
public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> { public class DownloadTask extends AbsNormalTask<DownloadEntity> {
public static final String TAG = "DownloadTask"; public static final String TAG = "DownloadTask";
private IDownloadListener mListener; private DListener<DownloadEntity, DownloadTask> mListener;
private Handler mOutHandler; private SimpleDownloadUtil mUtil;
private IDownloadUtil mUtil;
private boolean isWait = false;
private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) { private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) {
mEntity = taskEntity.downloadEntity; mEntity = taskEntity.getEntity();
mOutHandler = outHandler; mOutHandler = outHandler;
mContext = AriaManager.APP; mContext = AriaManager.APP;
mListener = new DListener(mContext, this, mOutHandler); mListener = new DListener<>(this, mOutHandler);
mUtil = new DownloadUtil(mContext, taskEntity, mListener); mUtil = new SimpleDownloadUtil(taskEntity, mListener);
} }
/** /**
@ -98,7 +90,6 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
* 暂停任务并让任务处于等待状态 * 暂停任务并让任务处于等待状态
*/ */
@Override public void stopAndWait() { @Override public void stopAndWait() {
super.stopAndWait();
stop(true); stop(true);
} }
@ -115,13 +106,10 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
* 开始下载 * 开始下载
*/ */
@Override public void start() { @Override public void start() {
isWait = false; mListener.isWait = false;
if (mUtil.isDownloading()) { if (mUtil.isDownloading()) {
Log.d(TAG, "任务正在下载"); Log.d(TAG, "任务正在下载");
} else { } else {
if (mListener == null || isWait) {
mListener = new DListener(mContext, this, mOutHandler);
}
mUtil.startDownload(); mUtil.startDownload();
} }
} }
@ -134,20 +122,15 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
} }
private void stop(boolean isWait) { private void stop(boolean isWait) {
this.isWait = isWait; mListener.isWait = isWait;
if (mUtil.isDownloading()) { if (mUtil.isDownloading()) {
mUtil.stopDownload(); mUtil.stopDownload();
} else { } else {
mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP); mEntity.setState(isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
mEntity.save(); mEntity.update();
if (mOutHandler != null) { if (mOutHandler != null) {
mOutHandler.obtainMessage(DownloadSchedulers.STOP, this).sendToTarget(); mOutHandler.obtainMessage(ISchedulers.STOP, this).sendToTarget();
} }
// 发送停止下载的广播
Intent intent = CommonUtil.createIntent(mContext.getPackageName(), Aria.ACTION_STOP);
intent.putExtra(Aria.CURRENT_LOCATION, mEntity.getCurrentProgress());
intent.putExtra(Aria.DOWNLOAD_ENTITY, mEntity);
mContext.sendBroadcast(intent);
} }
} }
@ -155,20 +138,13 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
* 取消下载 * 取消下载
*/ */
@Override public void cancel() { @Override public void cancel() {
if (!mEntity.isDownloadComplete()) { if (!mEntity.isComplete()) {
if (!mUtil.isDownloading()) { if (!mUtil.isDownloading()) {
if (mOutHandler != null) { if (mOutHandler != null) {
mOutHandler.obtainMessage(DownloadSchedulers.CANCEL, this).sendToTarget(); mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
} }
//发送取消下载的广播
Intent intent = CommonUtil.createIntent(mContext.getPackageName(), Aria.ACTION_CANCEL);
intent.putExtra(Aria.DOWNLOAD_ENTITY, mEntity);
mContext.sendBroadcast(intent);
} }
mUtil.cancelDownload(); mUtil.cancelDownload();
mUtil.delConfigFile();
mUtil.delTempFile();
mEntity.deleteData();
} }
} }
@ -178,7 +154,6 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
String targetName; String targetName;
public Builder(String targetName, DownloadTaskEntity taskEntity) { public Builder(String targetName, DownloadTaskEntity taskEntity) {
CheckUtil.checkTaskEntity(taskEntity);
this.targetName = targetName; this.targetName = targetName;
this.taskEntity = taskEntity; this.taskEntity = taskEntity;
} }
@ -196,162 +171,9 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
public DownloadTask build() { public DownloadTask build() {
DownloadTask task = new DownloadTask(taskEntity, outHandler); DownloadTask task = new DownloadTask(taskEntity, outHandler);
task.setTargetName(targetName); task.setTargetName(targetName);
taskEntity.downloadEntity.save(); taskEntity.getEntity().save();
taskEntity.save();
return task; return task;
} }
} }
/**
* 下载监听类
*/
private static class DListener extends DownloadListener {
WeakReference<Handler> outHandler;
WeakReference<DownloadTask> wTask;
Context context;
Intent sendIntent;
long lastLen = 0; //上一次发送长度
long lastTime = 0;
long INTERVAL_TIME = 1000; //1m更新周期
boolean isFirst = true;
DownloadEntity downloadEntity;
DownloadTask task;
boolean isOpenBroadCast = false;
boolean isConvertSpeed = false;
DListener(Context context, DownloadTask task, Handler outHandler) {
this.context = context;
this.outHandler = new WeakReference<>(outHandler);
this.wTask = new WeakReference<>(task);
this.task = wTask.get();
this.downloadEntity = this.task.getDownloadEntity();
sendIntent = CommonUtil.createIntent(context.getPackageName(), Aria.ACTION_RUNNING);
sendIntent.putExtra(Aria.DOWNLOAD_ENTITY, downloadEntity);
final AriaManager manager = AriaManager.getInstance(context);
isOpenBroadCast = manager.getDownloadConfig().isOpenBreadCast();
isConvertSpeed = manager.getDownloadConfig().isConvertSpeed();
}
@Override public void supportBreakpoint(boolean support) {
super.supportBreakpoint(support);
if (!support) {
sendInState2Target(ISchedulers.SUPPORT_BREAK_POINT);
sendIntent(Aria.ACTION_SUPPORT_BREAK_POINT, -1);
}
}
@Override public void onPre() {
super.onPre();
downloadEntity.setState(IEntity.STATE_PRE);
sendInState2Target(ISchedulers.PRE);
sendIntent(Aria.ACTION_PRE, -1);
}
@Override public void onPostPre(long fileSize) {
super.onPostPre(fileSize);
downloadEntity.setFileSize(fileSize);
downloadEntity.setState(IEntity.STATE_POST_PRE);
sendInState2Target(ISchedulers.POST_PRE);
sendIntent(Aria.ACTION_POST_PRE, -1);
}
@Override public void onResume(long resumeLocation) {
super.onResume(resumeLocation);
downloadEntity.setState(IEntity.STATE_RUNNING);
sendInState2Target(ISchedulers.RESUME);
sendIntent(Aria.ACTION_RESUME, resumeLocation);
}
@Override public void onStart(long startLocation) {
super.onStart(startLocation);
downloadEntity.setState(IEntity.STATE_RUNNING);
sendInState2Target(ISchedulers.START);
sendIntent(Aria.ACTION_START, startLocation);
}
@Override public void onProgress(long currentLocation) {
super.onProgress(currentLocation);
if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
long speed = currentLocation - lastLen;
sendIntent.putExtra(Aria.CURRENT_LOCATION, currentLocation);
sendIntent.putExtra(Aria.CURRENT_SPEED, speed);
lastTime = System.currentTimeMillis();
if (isFirst) {
speed = 0;
isFirst = false;
}
handleSpeed(speed);
downloadEntity.setCurrentProgress(currentLocation);
lastLen = currentLocation;
sendInState2Target(ISchedulers.RUNNING);
context.sendBroadcast(sendIntent);
}
}
@Override public void onStop(long stopLocation) {
super.onStop(stopLocation);
downloadEntity.setState(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_STOP);
handleSpeed(0);
sendInState2Target(ISchedulers.STOP);
sendIntent(Aria.ACTION_STOP, stopLocation);
}
@Override public void onCancel() {
super.onCancel();
downloadEntity.setState(IEntity.STATE_CANCEL);
handleSpeed(0);
sendInState2Target(ISchedulers.CANCEL);
sendIntent(Aria.ACTION_CANCEL, -1);
downloadEntity.deleteData();
}
@Override public void onComplete() {
super.onComplete();
downloadEntity.setState(IEntity.STATE_COMPLETE);
downloadEntity.setDownloadComplete(true);
handleSpeed(0);
sendInState2Target(ISchedulers.COMPLETE);
sendIntent(Aria.ACTION_COMPLETE, downloadEntity.getFileSize());
}
@Override public void onFail() {
super.onFail();
downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
downloadEntity.setState(IEntity.STATE_FAIL);
handleSpeed(0);
sendInState2Target(ISchedulers.FAIL);
sendIntent(Aria.ACTION_FAIL, -1);
}
private void handleSpeed(long speed) {
if (isConvertSpeed) {
downloadEntity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
} else {
downloadEntity.setSpeed(speed);
}
}
/**
* 将任务状态发送给下载器
*
* @param state {@link DownloadSchedulers#START}
*/
private void sendInState2Target(int state) {
if (outHandler.get() != null) {
outHandler.get().obtainMessage(state, task).sendToTarget();
}
}
private void sendIntent(String action, long location) {
downloadEntity.setDownloadComplete(action.equals(Aria.ACTION_COMPLETE));
downloadEntity.setCurrentProgress(location);
downloadEntity.update();
if (!isOpenBroadCast) return;
Intent intent = CommonUtil.createIntent(context.getPackageName(), action);
intent.putExtra(Aria.DOWNLOAD_ENTITY, downloadEntity);
if (location != -1) {
intent.putExtra(Aria.CURRENT_LOCATION, location);
}
context.sendBroadcast(intent);
}
}
} }

@ -16,22 +16,30 @@
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.OneToOne;
/** /**
* Created by lyy on 2017/1/23. * Created by lyy on 2017/1/23.
* 下载任务实体 * 下载任务实体
*/ */
public class DownloadTaskEntity extends AbsTaskEntity { public class DownloadTaskEntity extends AbsTaskEntity<DownloadEntity> {
public DownloadEntity downloadEntity; @OneToOne(table = DownloadEntity.class, key = "downloadPath") public DownloadEntity entity;
public DownloadTaskEntity(){} /**
* 所属的任务组组名如果不属于任务组则为null
*/
public String groupName = "";
/**
* 该任务是否属于任务组
*/
public boolean isGroupTask = false;
public DownloadTaskEntity(DownloadEntity downloadEntity) { public DownloadTaskEntity() {
this.downloadEntity = downloadEntity;
} }
@Override public DownloadEntity getEntity() { @Override public DownloadEntity getEntity() {
return downloadEntity; return entity;
} }
} }

@ -1,493 +0,0 @@
/*
* 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.download;
import android.content.Context;
import android.util.Log;
import android.util.SparseArray;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by lyy on 2015/8/25.
* 下载工具类
*/
class DownloadUtil implements IDownloadUtil, Runnable {
private static final String TAG = "DownloadUtil";
/**
* 线程数
*/
private int THREAD_NUM;
/**
* 小于1m的文件不启用多线程
*/
private static final long SUB_LEN = 1024 * 1024;
//下载监听
private IDownloadListener mListener;
private int mConnectTimeOut = 0; //连接超时时间
private boolean isNewTask = true;
private boolean isSupportBreakpoint = true;
private Context mContext;
private DownloadEntity mDownloadEntity;
private DownloadTaskEntity mDownloadTaskEntity;
private ExecutorService mFixedThreadPool;
private File mDownloadFile; //下载的文件
private File mConfigFile;//下载信息配置文件
private SparseArray<Runnable> mTask = new SparseArray<>();
private DownloadStateConstance CONSTANCE;
DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener) {
mDownloadEntity = entity.downloadEntity;
mContext = context.getApplicationContext();
mDownloadTaskEntity = entity;
mListener = downloadListener;
// 线程下载数改变后,新的下载才会生效
//mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE);
CONSTANCE = new DownloadStateConstance();
init();
}
private void init() {
mConnectTimeOut = AriaManager.getInstance(mContext).getDownloadConfig().getConnectTimeOut();
mDownloadFile = new File(mDownloadTaskEntity.downloadEntity.getDownloadPath());
//读取已完成的线程数
mConfigFile = new File(mContext.getFilesDir().getPath()
+ AriaManager.DOWNLOAD_TEMP_DIR
+ mDownloadFile.getName()
+ ".properties");
try {
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
isNewTask = true;
CommonUtil.createFile(mConfigFile.getPath());
} else {
isNewTask = !mDownloadFile.exists();
}
} catch (Exception e) {
e.printStackTrace();
failDownload("下载失败,记录文件被删除");
}
}
public IDownloadListener getListener() {
return mListener;
}
/**
* 获取当前下载位置
*/
@Override public long getCurrentLocation() {
return CONSTANCE.CURRENT_LOCATION;
}
@Override public boolean isDownloading() {
return CONSTANCE.isDownloading;
}
public void setMaxSpeed(double maxSpeed) {
for (int i = 0; i < THREAD_NUM; i++) {
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
if (task != null) {
task.setMaxSpeed(maxSpeed);
}
}
}
/**
* 取消下载
*/
@Override public void cancelDownload() {
CONSTANCE.isCancel = true;
CONSTANCE.isDownloading = false;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < THREAD_NUM; i++) {
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
if (task != null) {
task.cancel();
}
}
}
/**
* 停止下载
*/
@Override public void stopDownload() {
CONSTANCE.isStop = true;
CONSTANCE.isDownloading = false;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < THREAD_NUM; i++) {
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
if (task != null) {
task.stop();
}
}
}
/**
* 删除下载记录文件
*/
@Override public void delConfigFile() {
if (mContext != null && mDownloadEntity != null) {
File dFile = new File(mDownloadEntity.getDownloadPath());
File config =
new File(mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
if (config.exists()) {
config.delete();
}
}
}
/**
* 删除temp文件
*/
@Override public void delTempFile() {
if (mContext != null && mDownloadEntity != null) {
File dFile = new File(mDownloadEntity.getDownloadPath());
if (dFile.exists()) {
dFile.delete();
}
}
}
/**
* 多线程断点续传下载文件开始下载
*/
@Override public void startDownload() {
CONSTANCE.cleanState();
mListener.onPre();
new Thread(this).start();
}
@Override public void resumeDownload() {
startDownload();
}
private void failDownload(String msg) {
Log.e(TAG, msg);
CONSTANCE.isDownloading = false;
stopDownload();
mListener.onFail();
}
@Override public void run() {
try {
URL url = new URL(mDownloadEntity.getDownloadUrl());
HttpURLConnection conn = ConnectionHelp.handleConnection(url);
conn = ConnectionHelp.setConnectParam(mDownloadTaskEntity, conn);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
conn.setConnectTimeout(mConnectTimeOut);
conn.connect();
handleConnect(conn);
} catch (IOException e) {
failDownload("下载失败【downloadUrl:"
+ mDownloadEntity.getDownloadUrl()
+ "】\n【filePath:"
+ mDownloadFile.getPath()
+ "】"
+ CommonUtil.getPrintException(e));
}
}
/**
* 处理状态吗
*/
private void handleConnect(HttpURLConnection conn) throws IOException {
int len = conn.getContentLength();
//if (len < 0) { //网络被劫持时会出现这个问题
// failDownload("下载失败,网络被劫持");
// return;
//}
int code = conn.getResponseCode();
//https://zh.wikipedia.org/wiki/HTTP%E7%8A%B6%E6%80%81%E7%A0%81
//206支持断点
if (code == HttpURLConnection.HTTP_PARTIAL) {
if (!checkLen(len)) return;
isSupportBreakpoint = true;
mListener.supportBreakpoint(true);
handleBreakpoint(conn);
} else if (code == HttpURLConnection.HTTP_OK) {
//在conn.setRequestProperty("Range", "bytes=" + 0 + "-");下,200为不支持断点状态
if (!checkLen(len)) return;
isSupportBreakpoint = false;
mListener.supportBreakpoint(false);
Log.w(TAG, "该下载链接不支持断点下载");
handleBreakpoint(conn);
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
Log.w(TAG, "任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,错误码:404");
mListener.onCancel();
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER) {
handle302Turn(conn);
} else {
failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,错误码:" + code);
}
}
/**
* 检查长度是否合法
*
* @param len 从服务器获取的文件长度
* @return true, 合法
*/
private boolean checkLen(long len) {
if (len < 0) {
failDownload("任务【" + mDownloadEntity.getDownloadUrl() + "】下载失败,文件长度小于0");
return false;
}
return true;
}
/**
* 处理30x跳转
*/
private void handle302Turn(HttpURLConnection conn) throws IOException {
String newUrl = conn.getHeaderField(mDownloadTaskEntity.redirectUrlKey);
Log.d(TAG, "30x跳转,新url为【" + newUrl + "】");
mDownloadEntity.setRedirect(true);
mDownloadEntity.setRedirectUrl(newUrl);
mDownloadEntity.update();
String cookies = conn.getHeaderField("Set-Cookie");
conn = (HttpURLConnection) new URL(newUrl).openConnection();
conn = ConnectionHelp.setConnectParam(mDownloadTaskEntity, conn);
conn.setRequestProperty("Cookie", cookies);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
conn.setConnectTimeout(mConnectTimeOut);
conn.connect();
handleConnect(conn);
}
/**
* 处理断点
*/
private void handleBreakpoint(HttpURLConnection conn) throws IOException {
//不支持断点只能单线程下载
if (!isSupportBreakpoint) {
handleNoSupportBreakpointDownload(conn);
return;
}
int fileLength = conn.getContentLength();
Properties pro = createConfigFile(fileLength);
int blockSize = fileLength / THREAD_NUM;
int[] recordL = new int[THREAD_NUM];
int rl = 0;
for (int i = 0; i < THREAD_NUM; i++) {
recordL[i] = -1;
}
for (int i = 0; i < THREAD_NUM; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize;
Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
if (resumeRecordLocation(i, startL, endL)) return;
continue;
}
//分配下载位置
Object record = pro.getProperty(mDownloadFile.getName() + "_record_" + i);
//如果有记录,则恢复下载
if (!isNewTask && record != null && Long.parseLong(record + "") > 0) {
Long r = Long.parseLong(record + "");
CONSTANCE.CURRENT_LOCATION += r - startL;
Log.d(TAG, "任务【" + mDownloadEntity.getFileName() + "】线程__" + i + "__恢复下载");
mListener.onChildResume(r);
startL = r;
recordL[rl] = i;
rl++;
} else {
handleNewTask(fileLength);
}
if (isNewTask) {
recordL[rl] = i;
rl++;
}
if (i == (THREAD_NUM - 1)) {
//最后一个线程的结束位置即为文件的总长度
endL = fileLength;
}
addSingleTask(i, startL, endL, fileLength);
}
startSingleTask(recordL);
}
/**
* 处理不支持断点的下载
*/
private void handleNoSupportBreakpointDownload(HttpURLConnection conn) {
ConfigEntity entity = new ConfigEntity();
long len = conn.getContentLength();
entity.FILE_SIZE = len;
entity.DOWNLOAD_URL = mDownloadEntity.isRedirect() ? mDownloadEntity.getRedirectUrl()
: mDownloadEntity.getDownloadUrl();
entity.TEMP_FILE = mDownloadFile;
entity.THREAD_ID = 0;
entity.START_LOCATION = 0;
entity.END_LOCATION = entity.FILE_SIZE;
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
entity.isSupportBreakpoint = isSupportBreakpoint;
entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity;
THREAD_NUM = 1;
CONSTANCE.THREAD_NUM = THREAD_NUM;
SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity);
mTask.put(0, task);
mFixedThreadPool.execute(task);
mListener.onPostPre(len);
mListener.onStart(0);
}
/**
* 创建配置文件
*/
private Properties createConfigFile(long fileLength) throws IOException {
Properties pro = null;
//必须建一个文件
CommonUtil.createFile(mDownloadFile.getPath());
BufferedRandomAccessFile file =
new BufferedRandomAccessFile(new File(mDownloadFile.getPath()), "rwd", 8192);
//设置文件长度
file.setLength(fileLength);
mListener.onPostPre(fileLength);
//分配每条线程的下载区间
pro = CommonUtil.loadConfig(mConfigFile);
if (pro.isEmpty()) {
handleNewTask(fileLength);
} else {
Set<Object> keys = pro.keySet();
int num = 0;
for (Object key : keys) {
if (String.valueOf(key).contains("_record_")) {
num++;
}
}
if (num == 0) {
handleNewTask(fileLength);
return pro;
}
THREAD_NUM = num;
for (int i = 0; i < THREAD_NUM; i++) {
if (pro.getProperty(mDownloadFile.getName() + "_record_" + i) == null) {
Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) {
continue;
}
handleNewTask(fileLength);
return pro;
}
}
isNewTask = false;
}
return pro;
}
/**
* 处理新任务
*/
private void handleNewTask(long fileLength) {
isNewTask = true;
THREAD_NUM = fileLength < SUB_LEN ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum();
}
/**
* 恢复记录地址
*
* @return true 表示下载完成
*/
private boolean resumeRecordLocation(int i, long startL, long endL) {
CONSTANCE.CURRENT_LOCATION += endL - startL;
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
CONSTANCE.COMPLETE_THREAD_NUM++;
CONSTANCE.STOP_NUM++;
CONSTANCE.CANCEL_NUM++;
if (CONSTANCE.isComplete()) {
if (mConfigFile.exists()) {
mConfigFile.delete();
}
mListener.onComplete();
CONSTANCE.isDownloading = false;
return true;
}
return false;
}
/**
* 创建单线程任务
*/
private void addSingleTask(int i, long startL, long endL, long fileLength) {
ConfigEntity entity = new ConfigEntity();
entity.FILE_SIZE = fileLength;
entity.DOWNLOAD_URL = mDownloadEntity.isRedirect() ? mDownloadEntity.getRedirectUrl()
: mDownloadEntity.getDownloadUrl();
entity.TEMP_FILE = mDownloadFile;
entity.THREAD_ID = i;
entity.START_LOCATION = startL;
entity.END_LOCATION = endL;
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
entity.isSupportBreakpoint = isSupportBreakpoint;
entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity;
CONSTANCE.THREAD_NUM = THREAD_NUM;
SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity);
mTask.put(i, task);
}
/**
* 启动单线程下载任务
*/
private void startSingleTask(int[] recordL) {
if (CONSTANCE.CURRENT_LOCATION > 0) {
mListener.onResume(CONSTANCE.CURRENT_LOCATION);
} else {
mListener.onStart(CONSTANCE.CURRENT_LOCATION);
}
mFixedThreadPool = Executors.newFixedThreadPool(recordL.length);
for (int l : recordL) {
if (l == -1) continue;
Runnable task = mTask.get(l);
if (task != null) {
mFixedThreadPool.execute(task);
}
}
}
/**
* 子线程下载信息类
*/
final static class ConfigEntity {
//文件大小
int THREAD_ID;
long FILE_SIZE;
long START_LOCATION;
long END_LOCATION;
File TEMP_FILE;
String DOWNLOAD_URL;
String CONFIG_FILE_PATH;
DownloadTaskEntity DOWNLOAD_TASK_ENTITY;
boolean isSupportBreakpoint = true;
}
}

@ -0,0 +1,24 @@
package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import java.io.File;
/**
* 子线程下载信息类
*/
final class ChildThreadConfigEntity {
//线程Id
int THREAD_ID;
//下载文件大小
long FILE_SIZE;
//子线程启动下载位置
long START_LOCATION;
//子线程结束下载位置
long END_LOCATION;
//下载路径
File TEMP_FILE;
String DOWNLOAD_URL;
String CONFIG_FILE_PATH;
DownloadTaskEntity DOWNLOAD_TASK_ENTITY;
boolean IS_SUPPORT_BREAK_POINT = true;
}

@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download.downloader;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.SSLContextUtil; import com.arialyy.aria.util.SSLContextUtil;
import java.io.IOException; import java.io.IOException;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;

@ -0,0 +1,403 @@
/*
* 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.download.downloader;
import android.util.SparseArray;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by AriaL on 2017/6/30.
* 任务组下载工具
*/
public class DownloadGroupUtil implements IDownloadUtil {
private final String TAG = "DownloadGroupUtil";
/**
* 任务组所有任务总大小
*/
private long mTotalSize = 0;
private long mCurrentLocation = 0;
private ExecutorService mInfoPool;
private ExecutorService mExePool;
private IDownloadListener mListener;
private DownloadGroupTaskEntity mTaskEntity;
private boolean isRunning = true;
private Timer mTimer;
/**
* 初始化完成的任务书数
*/
private int mInitNum = 0;
/**
* 初始化失败的任务数
*/
private int mInitFailNum = 0;
/**
* 保存所有没有下载完成的任务key为下载地址
*/
private Map<String, DownloadTaskEntity> mExeMap = new HashMap<>();
/**
* 下载失败的映射表key为下载地址
*/
private Map<String, DownloadTaskEntity> mFailMap = new HashMap<>();
/**
* 下载器映射表key为下载地址
*/
private Map<String, Downloader> mDownloaderMap = new HashMap<>();
/**
* 文件信息回调组
*/
private SparseArray<FileInfoThread.OnFileInfoCallback> mFileInfoCallbacks = new SparseArray<>();
/**
* 该任务组对应的所有任务
*/
private Map<String, DownloadTaskEntity> mTasksMap = new HashMap<>();
//已经完成的任务数
private int mCompleteNum = 0;
//失败的任务数
private int mFailNum = 0;
//实际的下载任务数
private int mActualTaskNum = 0;
public DownloadGroupUtil(IDownloadListener listener, DownloadGroupTaskEntity taskEntity) {
mListener = listener;
mTaskEntity = taskEntity;
mInfoPool = Executors.newCachedThreadPool();
mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
mActualTaskNum = mTaskEntity.entity.getSubTask().size();
List<DownloadTaskEntity> tasks =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mTaskEntity.key);
if (tasks != null && !tasks.isEmpty()) {
for (DownloadTaskEntity te : tasks) {
mTasksMap.put(te.getEntity().getDownloadUrl(), te);
}
}
for (DownloadEntity entity : mTaskEntity.entity.getSubTask()) {
File file = new File(entity.getDownloadPath());
if (entity.isComplete() && file.exists()) {
mTotalSize += entity.getFileSize();
mCompleteNum++;
mInitNum++;
mCurrentLocation += entity.getFileSize();
} else {
mExeMap.put(entity.getDownloadUrl(), createChildDownloadTask(entity));
mCurrentLocation += entity.getCurrentProgress();
}
}
}
@Override public long getFileSize() {
return mTotalSize;
}
@Override public long getCurrentLocation() {
return mCurrentLocation;
}
@Override public boolean isDownloading() {
return isRunning;
}
@Override public void cancelDownload() {
isRunning = false;
closeTimer();
mListener.onCancel();
if (!mInfoPool.isShutdown()) {
mInfoPool.shutdown();
}
if (!mExePool.isShutdown()) {
mExePool.shutdown();
}
Set<String> keys = mDownloaderMap.keySet();
for (String key : keys) {
Downloader dt = mDownloaderMap.get(key);
if (dt != null) {
dt.cancelDownload();
}
}
delDownloadInfo();
mTaskEntity.deleteData();
}
/**
* 删除所有子任务的下载信息
*/
private void delDownloadInfo() {
List<DownloadTaskEntity> tasks =
DbEntity.findDatas(DownloadTaskEntity.class, "groupName=?", mTaskEntity.key);
if (tasks == null || tasks.isEmpty()) return;
for (DownloadTaskEntity taskEntity : tasks) {
CommonUtil.delDownloadTaskConfig(taskEntity.removeFile, taskEntity);
}
}
@Override public void stopDownload() {
isRunning = false;
closeTimer();
mListener.onStop(mCurrentLocation);
if (!mInfoPool.isShutdown()) {
mInfoPool.shutdown();
}
if (!mExePool.isShutdown()) {
mExePool.shutdown();
}
Set<String> keys = mDownloaderMap.keySet();
for (String key : keys) {
Downloader dt = mDownloaderMap.get(key);
if (dt != null) {
dt.stopDownload();
}
}
}
@Override public void startDownload() {
isRunning = true;
Set<String> keys = mExeMap.keySet();
mListener.onPre();
for (String key : keys) {
DownloadTaskEntity taskEntity = mExeMap.get(key);
if (taskEntity != null) {
mInfoPool.execute(createFileInfoThread(taskEntity));
}
}
}
@Override public void resumeDownload() {
startDownload();
mListener.onResume(mCurrentLocation);
}
/**
* 创建文件信息获取线程
*/
private FileInfoThread createFileInfoThread(DownloadTaskEntity taskEntity) {
FileInfoThread.OnFileInfoCallback callback = mFileInfoCallbacks.get(taskEntity.hashCode());
if (callback == null) {
callback = new FileInfoThread.OnFileInfoCallback() {
int failNum = 0;
@Override public void onComplete(String url, int code) {
DownloadTaskEntity te = mExeMap.get(url);
if (te != null) {
mTotalSize += te.getEntity().getFileSize();
startChildDownload(te);
}
mInitNum++;
if (mInitNum + mInitFailNum == mTaskEntity.getEntity().getSubTask().size()) {
startRunningFlow();
}
}
@Override public void onFail(String url, String errorMsg) {
DownloadTaskEntity te = mExeMap.get(url);
if (te != null) {
mFailMap.put(url, te);
mFileInfoCallbacks.put(te.hashCode(), this);
}
//404链接不重试下载
if (failNum < 10 && !errorMsg.contains("错误码:404") && !errorMsg.contains(
"UnknownHostException")) {
mInfoPool.execute(createFileInfoThread(te));
} else {
mInitFailNum++;
mActualTaskNum--;
if (mActualTaskNum < 0) mActualTaskNum = 0;
}
failNum++;
if (mInitNum + mInitFailNum == mTaskEntity.getEntity().getSubTask().size()) {
startRunningFlow();
}
}
};
}
return new FileInfoThread(taskEntity, callback);
}
private void closeTimer() {
if (mTimer != null) {
mTimer.purge();
mTimer.cancel();
}
}
/**
* 开始进度流程
*/
private void startRunningFlow() {
closeTimer();
mListener.onPostPre(mTotalSize);
mListener.onStart(mCurrentLocation);
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
@Override public void run() {
if (mCurrentLocation >= 0) {
mListener.onProgress(mCurrentLocation);
}
}
}, 0, 1000);
}
/**
* 启动子任务下载器
*/
private void startChildDownload(DownloadTaskEntity taskEntity) {
ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
Downloader dt = new Downloader(listener, taskEntity);
mDownloaderMap.put(taskEntity.getEntity().getDownloadUrl(), dt);
if (mExePool.isShutdown()) return;
mExePool.execute(dt);
}
/**
* 创建子任务下载信息
*/
private DownloadTaskEntity createChildDownloadTask(DownloadEntity entity) {
DownloadTaskEntity taskEntity = mTasksMap.get(entity.getDownloadUrl());
if (taskEntity != null) {
taskEntity.entity = entity;
return taskEntity;
}
taskEntity = new DownloadTaskEntity();
taskEntity.entity = entity;
taskEntity.headers = mTaskEntity.headers;
taskEntity.requestEnum = mTaskEntity.requestEnum;
taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey;
taskEntity.removeFile = mTaskEntity.removeFile;
taskEntity.groupName = mTaskEntity.key;
taskEntity.isGroupTask = true;
taskEntity.key = entity.getDownloadPath();
taskEntity.save();
return taskEntity;
}
/**
* 子任务事件监听
*/
private class ChildDownloadListener extends DownloadListener {
DownloadTaskEntity taskEntity;
DownloadEntity entity;
long lastLen = 0;
ChildDownloadListener(DownloadTaskEntity entity) {
this.taskEntity = entity;
this.entity = taskEntity.getEntity();
}
@Override public void onPre() {
saveData(IEntity.STATE_PRE, -1);
}
@Override public void onPostPre(long fileSize) {
entity.setFileSize(fileSize);
entity.setConvertFileSize(CommonUtil.formatFileSize(fileSize));
saveData(IEntity.STATE_POST_PRE, -1);
}
@Override public void onResume(long resumeLocation) {
saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
lastLen = resumeLocation;
}
@Override public void onStart(long startLocation) {
saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
lastLen = startLocation;
}
@Override public void onProgress(long currentLocation) {
long speed = currentLocation - lastLen;
mCurrentLocation += speed;
lastLen = currentLocation;
entity.setCurrentProgress(currentLocation);
handleSpeed(speed);
}
@Override public void onStop(long stopLocation) {
saveData(IEntity.STATE_STOP, stopLocation);
handleSpeed(0);
}
@Override public void onCancel() {
saveData(IEntity.STATE_CANCEL, -1);
handleSpeed(0);
}
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
mCompleteNum++;
if (mCompleteNum + mFailNum >= mActualTaskNum) {
closeTimer();
mListener.onComplete();
}
handleSpeed(0);
}
@Override public void onFail() {
entity.setFailNum(entity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, -1);
handleSpeed(0);
reTry();
}
/**
* 失败后重试下载如果失败次数超过5次不再重试
*/
private void reTry() {
if (entity.getFailNum() < 5) {
Downloader dt = mDownloaderMap.get(entity.getDownloadUrl());
dt.startDownload();
} else {
mFailNum++;
}
}
private void handleSpeed(long speed) {
entity.setSpeed(speed);
entity.setConvertSpeed(speed <= 0 ? "" : CommonUtil.formatFileSize(speed) + "/s");
}
private void saveData(int state, long location) {
entity.setState(state);
entity.setComplete(state == IEntity.STATE_COMPLETE);
if (entity.isComplete()) {
entity.setCompleteTime(System.currentTimeMillis());
entity.setCurrentProgress(entity.getFileSize());
} else {
entity.setCurrentProgress(location);
}
entity.update();
}
}
}

@ -14,12 +14,13 @@
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download.downloader;
/** /**
* @author lyy * @author lyy
*/ */
class DownloadListener implements IDownloadListener { public class DownloadListener implements IDownloadListener {
@Override public void onResume(long resumeLocation) { @Override public void onResume(long resumeLocation) {

@ -0,0 +1,420 @@
/*
* 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.download.downloader;
import android.content.Context;
import android.util.Log;
import android.util.SparseArray;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.BufferedRandomAccessFile;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* Created by AriaL on 2017/7/1.
* 文件下载器
*/
class Downloader implements Runnable, IDownloadUtil {
private final String TAG = "Downloader";
private IDownloadListener mListener;
private DownloadTaskEntity mTaskEntity;
private DownloadEntity mEntity;
private ExecutorService mFixedThreadPool;
private File mConfigFile;//下载信息配置文件
private Context mContext;
private File mTempFile; //下载的文件
private boolean isNewTask = true;
private int mThreadNum, mRealThreadNum;
private StateConstance mConstance;
private SparseArray<Runnable> mTask = new SparseArray<>();
/**
* 小于1m的文件不启用多线程
*/
private static final long SUB_LEN = 1024 * 1024;
private Timer mTimer;
Downloader(IDownloadListener listener, DownloadTaskEntity taskEntity) {
mListener = listener;
mTaskEntity = taskEntity;
mEntity = mTaskEntity.getEntity();
mContext = AriaManager.APP;
mConstance = new StateConstance();
}
void setMaxSpeed(double maxSpeed) {
for (int i = 0; i < mThreadNum; i++) {
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
if (task != null) {
task.setMaxSpeed(maxSpeed);
}
}
}
public StateConstance getConstance() {
return mConstance;
}
@Override public void run() {
startFlow();
}
/**
* 开始下载流程
*/
private void startFlow() {
checkTask();
mListener.onPostPre(mEntity.getFileSize());
mConstance.cleanState();
mConstance.isDownloading = true;
if (!mTaskEntity.isSupportBP) {
mThreadNum = 1;
mConstance.THREAD_NUM = mThreadNum;
handleNoSupportBreakpointDownload();
} else {
mThreadNum = isNewTask ? (mEntity.getFileSize() <= SUB_LEN ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum()) : mRealThreadNum;
mConstance.THREAD_NUM = mThreadNum;
mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum);
handleBreakpoint();
}
startTimer();
}
/**
* 启动进度获取定时器
*/
private void startTimer() {
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
@Override public void run() {
if (mConstance.isComplete()) {
closeTimer();
} else if (mConstance.CURRENT_LOCATION >= 0) {
mListener.onProgress(mConstance.CURRENT_LOCATION);
}
}
}, 0, 1000);
}
private void closeTimer() {
if (mTimer != null) {
mTimer.purge();
mTimer.cancel();
}
}
@Override public long getFileSize() {
return mEntity.getFileSize();
}
/**
* 获取当前下载位置
*/
@Override public long getCurrentLocation() {
return mConstance.CURRENT_LOCATION;
}
@Override public boolean isDownloading() {
return mConstance.isDownloading;
}
@Override public void cancelDownload() {
closeTimer();
mConstance.isCancel = true;
mConstance.isDownloading = false;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < mThreadNum; i++) {
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
if (task != null) {
task.cancel();
}
}
CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, mTaskEntity);
}
@Override public void stopDownload() {
closeTimer();
if (mConstance.isComplete()) return;
mConstance.isStop = true;
mConstance.isDownloading = false;
if (mFixedThreadPool != null) {
mFixedThreadPool.shutdown();
}
for (int i = 0; i < mThreadNum; i++) {
SingleThreadTask task = (SingleThreadTask) mTask.get(i);
if (task != null) {
task.stop();
}
}
}
/**
* 直接调用的时候会自动启动线程执行
*/
@Override public void startDownload() {
new Thread(this).start();
}
@Override public void resumeDownload() {
startDownload();
}
/**
* 返回该下载器的
*/
public IDownloadListener getListener() {
return mListener;
}
/**
* 检查任务是否是新任务新任务条件
* 1文件不存在
* 2下载记录文件不存在
* 3下载记录文件缺失或不匹配
* 4数据库记录不存在
* 5不支持断点则是新任务
*/
private void checkTask() {
if (!mTaskEntity.isSupportBP) {
isNewTask = true;
return;
}
mConfigFile = new File(mContext.getFilesDir().getPath()
+ AriaManager.DOWNLOAD_TEMP_DIR
+ mEntity.getFileName()
+ ".properties");
mTempFile = new File(mEntity.getDownloadPath());
if (!mConfigFile.exists()) { //记录文件被删除,则重新下载
isNewTask = true;
CommonUtil.createFile(mConfigFile.getPath());
} else if (!mTempFile.exists()) {
isNewTask = true;
} else if (DbEntity.findFirst(DownloadEntity.class, "downloadUrl=?", mEntity.getDownloadUrl())
== null) {
isNewTask = true;
} else {
isNewTask = checkConfigFile();
}
}
/**
* 检查记录文件如果是新任务返回{@code true}否则返回{@code false}
*/
private boolean checkConfigFile() {
Properties pro = CommonUtil.loadConfig(mConfigFile);
if (pro.isEmpty()) {
return true;
}
Set<Object> keys = pro.keySet();
int num = 0;
for (Object key : keys) {
if (String.valueOf(key).contains("_record_")) {
num++;
}
}
if (num == 0) {
return true;
}
mRealThreadNum = num;
for (int i = 0; i < mRealThreadNum; i++) {
if (pro.getProperty(mTempFile.getName() + "_record_" + i) == null) {
Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) {
continue;
}
return true;
}
}
return false;
}
/**
* 恢复记录地址
*
* @return true 表示下载完成
*/
private boolean resumeRecordLocation(int i, long startL, long endL) {
mConstance.CURRENT_LOCATION += endL - startL;
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
mConstance.COMPLETE_THREAD_NUM++;
mConstance.STOP_NUM++;
mConstance.CANCEL_NUM++;
if (mConstance.isComplete()) {
if (mConfigFile.exists()) {
mConfigFile.delete();
}
mListener.onComplete();
mConstance.isDownloading = false;
return true;
}
return false;
}
/**
* 创建单线程任务
*/
private void addSingleTask(int i, long startL, long endL, long fileLength) {
ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
entity.FILE_SIZE = fileLength;
entity.DOWNLOAD_URL =
mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
entity.TEMP_FILE = mTempFile;
entity.THREAD_ID = i;
entity.START_LOCATION = startL;
entity.END_LOCATION = endL;
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity);
mTask.put(i, task);
}
/**
* 启动单线程下载任务
*/
private void startSingleTask(int[] recordL) {
if (mConstance.CURRENT_LOCATION > 0) {
mListener.onResume(mConstance.CURRENT_LOCATION);
} else {
mListener.onStart(mConstance.CURRENT_LOCATION);
}
mFixedThreadPool = Executors.newFixedThreadPool(recordL.length);
for (int l : recordL) {
if (l == -1) continue;
Runnable task = mTask.get(l);
if (task != null) {
mFixedThreadPool.execute(task);
}
}
}
/**
* 处理断点
*/
private void handleBreakpoint() {
long fileLength = mEntity.getFileSize();
Properties pro = CommonUtil.loadConfig(mConfigFile);
int blockSize = (int) (fileLength / mThreadNum);
int[] recordL = new int[mThreadNum];
for (int i = 0; i < mThreadNum; i++) {
recordL[i] = -1;
}
int rl = 0;
if (isNewTask) {
createNewFile(fileLength);
}
for (int i = 0; i < mThreadNum; i++) {
long startL = i * blockSize, endL = (i + 1) * blockSize;
Object state = pro.getProperty(mTempFile.getName() + "_state_" + i);
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
if (resumeRecordLocation(i, startL, endL)) return;
continue;
}
//分配下载位置
Object record = pro.getProperty(mTempFile.getName() + "_record_" + i);
//如果有记录,则恢复下载
if (!isNewTask && record != null && Long.parseLong(record + "") >= 0) {
Long r = Long.parseLong(record + "");
mConstance.CURRENT_LOCATION += r - startL;
Log.d(TAG, "任务【" + mEntity.getFileName() + "】线程__" + i + "__恢复下载");
mListener.onChildResume(r);
startL = r;
recordL[rl] = i;
rl++;
} else {
recordL[rl] = i;
rl++;
}
if (i == (mThreadNum - 1)) {
//最后一个线程的结束位置即为文件的总长度
endL = fileLength;
}
addSingleTask(i, startL, endL, fileLength);
}
startSingleTask(recordL);
}
/**
* 创建新的下载文件
*/
private void createNewFile(long fileLength) {
CommonUtil.createFile(mTempFile.getPath());
BufferedRandomAccessFile file = null;
try {
file = new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192);
//设置文件长度
file.setLength(fileLength);
} catch (IOException e) {
failDownload("下载失败【downloadUrl:"
+ mEntity.getDownloadUrl()
+ "】\n【filePath:"
+ mEntity.getDownloadPath()
+ "】\n"
+ CommonUtil.getPrintException(e));
} finally {
if (file != null) {
try {
file.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 处理不支持断点的下载
*/
private void handleNoSupportBreakpointDownload() {
ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
long len = mEntity.getFileSize();
entity.FILE_SIZE = len;
entity.DOWNLOAD_URL =
mEntity.isRedirect() ? mEntity.getRedirectUrl() : mEntity.getDownloadUrl();
entity.TEMP_FILE = mTempFile;
entity.THREAD_ID = 0;
entity.START_LOCATION = 0;
entity.END_LOCATION = entity.FILE_SIZE;
entity.CONFIG_FILE_PATH = mConfigFile.getPath();
entity.IS_SUPPORT_BREAK_POINT = mTaskEntity.isSupportBP;
entity.DOWNLOAD_TASK_ENTITY = mTaskEntity;
SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity);
mTask.put(0, task);
mFixedThreadPool.execute(task);
mListener.onPostPre(len);
mListener.onStart(0);
}
private void failDownload(String errorMsg) {
closeTimer();
Log.e(TAG, errorMsg);
mConstance.isDownloading = false;
mListener.onFail();
}
}

@ -0,0 +1,179 @@
/*
* 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.download.downloader;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.util.CommonUtil;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
/**
* 下载文件信息获取
*/
class FileInfoThread implements Runnable {
private final String TAG = "FileInfoThread";
private DownloadEntity mEntity;
private DownloadTaskEntity mTaskEntity;
private int mConnectTimeOut;
private OnFileInfoCallback onFileInfoListener;
interface OnFileInfoCallback {
/**
* 处理完成
*
* @param code 状态码
*/
void onComplete(String url, int code);
/**
* 请求失败
*
* @param errorMsg 错误信息
*/
void onFail(String url, String errorMsg);
}
FileInfoThread(DownloadTaskEntity taskEntity, OnFileInfoCallback callback) {
this.mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mConnectTimeOut =
AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getConnectTimeOut();
onFileInfoListener = callback;
}
@Override public void run() {
HttpURLConnection conn = null;
try {
URL url = new URL(mEntity.getDownloadUrl());
conn = ConnectionHelp.handleConnection(url);
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
conn.setConnectTimeout(mConnectTimeOut);
conn.connect();
handleConnect(conn);
} catch (IOException e) {
failDownload("下载失败【downloadUrl:"
+ mEntity.getDownloadUrl()
+ "】\n【filePath:"
+ mEntity.getDownloadPath()
+ "】\n"
+ CommonUtil.getPrintException(e));
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
private void handleConnect(HttpURLConnection conn) throws IOException {
int len = conn.getContentLength();
int code = conn.getResponseCode();
boolean isComplete = false;
if (TextUtils.isEmpty(mEntity.getMd5Code())) {
String md5Code = conn.getHeaderField(mTaskEntity.md5Key);
mEntity.setMd5Code(md5Code);
}
String disposition = conn.getHeaderField(mTaskEntity.dispositionKey);
if (!TextUtils.isEmpty(disposition)) {
mEntity.setDisposition(disposition);
if (disposition.contains(mTaskEntity.dispositionFileKey)) {
String[] infos = disposition.split("=");
mEntity.setServerFileName(URLDecoder.decode(infos[1], "utf-8"));
}
}
mTaskEntity.code = code;
if (code == HttpURLConnection.HTTP_PARTIAL) {
if (!checkLen(len)) return;
mEntity.setFileSize(len);
mTaskEntity.isSupportBP = true;
isComplete = true;
} else if (code == HttpURLConnection.HTTP_OK) {
if (!checkLen(len)) return;
mEntity.setFileSize(len);
mTaskEntity.isSupportBP = false;
isComplete = true;
} else if (code == HttpURLConnection.HTTP_NOT_FOUND) {
failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,错误码:404");
} else if (code == HttpURLConnection.HTTP_MOVED_TEMP
|| code == HttpURLConnection.HTTP_MOVED_PERM
|| code == HttpURLConnection.HTTP_SEE_OTHER) {
mTaskEntity.redirectUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
mEntity.setRedirect(true);
mEntity.setRedirectUrl(mTaskEntity.redirectUrl);
handle302Turn(conn);
} else {
failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,错误码:" + code);
}
if (isComplete) {
if (onFileInfoListener != null) {
onFileInfoListener.onComplete(mEntity.getDownloadUrl(), code);
}
mEntity.update();
mTaskEntity.update();
}
}
/**
* 处理30x跳转
*/
private void handle302Turn(HttpURLConnection conn) throws IOException {
String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
Log.d(TAG, "30x跳转,location【 " + mTaskEntity.redirectUrlKey + "】" + "新url为【" + newUrl + "】");
if (TextUtils.isEmpty(newUrl) || newUrl.equalsIgnoreCase("null")) {
if (onFileInfoListener != null) {
onFileInfoListener.onFail(mEntity.getDownloadUrl(), "获取重定向链接失败");
}
return;
}
String cookies = conn.getHeaderField("Set-Cookie");
conn = (HttpURLConnection) new URL(newUrl).openConnection();
conn = ConnectionHelp.setConnectParam(mTaskEntity, conn);
conn.setRequestProperty("Cookie", cookies);
conn.setRequestProperty("Range", "bytes=" + 0 + "-");
conn.setConnectTimeout(mConnectTimeOut);
conn.connect();
handleConnect(conn);
conn.disconnect();
}
/**
* 检查长度是否合法
*
* @param len 从服务器获取的文件长度
* @return true, 合法
*/
private boolean checkLen(long len) {
if (len < 0) {
failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,文件长度小于0");
return false;
}
return true;
}
private void failDownload(String errorMsg) {
Log.e(TAG, errorMsg);
if (onFileInfoListener != null) {
onFileInfoListener.onFail(mEntity.getDownloadUrl(), errorMsg);
}
}
}

@ -0,0 +1,42 @@
/*
* 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.download.downloader;
import com.arialyy.aria.core.inf.IEventListener;
/**
* 下载监听
*/
interface IDownloadListener extends IEventListener {
/**
* 支持断点回调
*
* @param support true,支持false 不支持
*/
void supportBreakpoint(boolean support);
/**
* 单一线程的结束位置
*/
void onChildComplete(long finishLocation);
/**
* 子程恢复下载的位置
*/
void onChildResume(long resumeLocation);
}

@ -14,58 +14,48 @@
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download.downloader;
/** /**
* Created by lyy on 2016/10/31. * Created by lyy on 2016/10/31.
* 抽象的下载接口 * 抽象的下载接口
*/ */
interface IDownloadUtil { public interface IDownloadUtil {
/**
* 获取文件大小
*/
long getFileSize();
/** /**
* 获取当前下载位置 * 获取当前下载位置
*/ */
public long getCurrentLocation(); long getCurrentLocation();
/** /**
* 是否正在下载 * 是否正在下载
* *
* @return true, 正在下载 * @return true, 正在下载
*/ */
public boolean isDownloading(); boolean isDownloading();
/** /**
* 取消下载 * 取消下载
*/ */
public void cancelDownload(); void cancelDownload();
/** /**
* 停止下载 * 停止下载
*/ */
public void stopDownload(); void stopDownload();
/** /**
* 开始下载 * 开始下载
*/ */
public void startDownload(); void startDownload();
/** /**
* 从上次断点恢复下载 * 从上次断点恢复下载
*/ */
public void resumeDownload(); void resumeDownload();
/**
* 删除下载记录文件
*/
public void delConfigFile();
/**
* 删除temp文件
*/
public void delTempFile();
/**
* 设置最大下载速度
*/
public void setMaxSpeed(double maxSpeed);
} }

@ -0,0 +1,104 @@
/*
* 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.download.downloader;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.download.DownloadTaskEntity;
/**
* Created by lyy on 2015/8/25.
* 简单的下载工具
*/
public class SimpleDownloadUtil implements IDownloadUtil, Runnable {
private static final String TAG = "SimpleDownloadUtil";
private IDownloadListener mListener;
private Downloader mDT;
private DownloadTaskEntity mTaskEntity;
public SimpleDownloadUtil(DownloadTaskEntity entity, IDownloadListener downloadListener) {
mTaskEntity = entity;
mListener = downloadListener;
mDT = new Downloader(downloadListener, entity);
}
@Override public long getFileSize() {
return mDT.getFileSize();
}
/**
* 获取当前下载位置
*/
@Override public long getCurrentLocation() {
return mDT.getCurrentLocation();
}
@Override public boolean isDownloading() {
return mDT.isDownloading();
}
/**
* 取消下载
*/
@Override public void cancelDownload() {
mDT.cancelDownload();
}
/**
* 停止下载
*/
@Override public void stopDownload() {
mDT.stopDownload();
}
/**
* 多线程断点续传下载文件开始下载
*/
@Override public void startDownload() {
mListener.onPre();
new Thread(this).start();
}
@Override public void resumeDownload() {
startDownload();
}
public void setMaxSpeed(double maxSpeed) {
mDT.setMaxSpeed(maxSpeed);
}
private void failDownload(String msg) {
Log.e(TAG, msg);
mListener.onFail();
}
@Override public void run() {
if (TextUtils.isEmpty(mTaskEntity.redirectUrl)) {
new Thread(new FileInfoThread(mTaskEntity, new FileInfoThread.OnFileInfoCallback() {
@Override public void onComplete(String url, int code) {
mDT.startDownload();
}
@Override public void onFail(String url, String errorMsg) {
failDownload(errorMsg);
}
})).start();
} else {
new Downloader(mListener, mTaskEntity).startDownload();
}
}
}

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download.downloader;
import android.os.Build; import android.os.Build;
import android.text.TextUtils; import android.text.TextUtils;
@ -28,9 +28,7 @@ import java.math.BigDecimal;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.MalformedURLException; import java.net.MalformedURLException;
import java.net.URL; import java.net.URL;
import java.util.HashSet;
import java.util.Properties; import java.util.Properties;
import java.util.Set;
/** /**
* Created by lyy on 2017/1/18. * Created by lyy on 2017/1/18.
@ -38,23 +36,23 @@ import java.util.Set;
*/ */
final class SingleThreadTask implements Runnable { final class SingleThreadTask implements Runnable {
private static final String TAG = "SingleThreadTask"; private static final String TAG = "SingleThreadTask";
private DownloadUtil.ConfigEntity mConfigEntity; private ChildThreadConfigEntity mConfigEntity;
private String mConfigFPath; private String mConfigFPath;
private long mChildCurrentLocation = 0; private long mChildCurrentLocation = 0;
private int mBufSize; private int mBufSize;
private IDownloadListener mListener; private IDownloadListener mListener;
private DownloadStateConstance CONSTANCE; private StateConstance CONSTANCE;
private long mSleepTime = 0; private long mSleepTime = 0;
SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener, SingleThreadTask(StateConstance constance, IDownloadListener listener,
DownloadUtil.ConfigEntity downloadInfo) { ChildThreadConfigEntity downloadInfo) {
AriaManager manager = AriaManager.getInstance(AriaManager.APP); AriaManager manager = AriaManager.getInstance(AriaManager.APP);
CONSTANCE = constance; CONSTANCE = constance;
CONSTANCE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut(); CONSTANCE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();
CONSTANCE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut(); CONSTANCE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut();
mListener = listener; mListener = listener;
this.mConfigEntity = downloadInfo; this.mConfigEntity = downloadInfo;
if (mConfigEntity.isSupportBreakpoint) { if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
mConfigFPath = downloadInfo.CONFIG_FILE_PATH; mConfigFPath = downloadInfo.CONFIG_FILE_PATH;
} }
mBufSize = manager.getDownloadConfig().getBuffSize(); mBufSize = manager.getDownloadConfig().getBuffSize();
@ -76,12 +74,13 @@ final class SingleThreadTask implements Runnable {
} }
@Override public void run() { @Override public void run() {
HttpURLConnection conn; HttpURLConnection conn = null;
InputStream is; InputStream is = null;
BufferedRandomAccessFile file = null;
try { try {
URL url = new URL(mConfigEntity.DOWNLOAD_URL); URL url = new URL(mConfigEntity.DOWNLOAD_URL);
conn = ConnectionHelp.handleConnection(url); conn = ConnectionHelp.handleConnection(url);
if (mConfigEntity.isSupportBreakpoint) { if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
Log.d(TAG, "任务【" Log.d(TAG, "任务【"
+ mConfigEntity.TEMP_FILE.getName() + mConfigEntity.TEMP_FILE.getName()
+ "】线程__" + "】线程__"
@ -102,8 +101,7 @@ final class SingleThreadTask implements Runnable {
conn.setReadTimeout(CONSTANCE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 conn.setReadTimeout(CONSTANCE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数
is = conn.getInputStream(); is = conn.getInputStream();
//创建可设置位置的文件 //创建可设置位置的文件
BufferedRandomAccessFile file = file = new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", mBufSize);
new BufferedRandomAccessFile(mConfigEntity.TEMP_FILE, "rwd", mBufSize);
//设置每条线程写入文件的位置 //设置每条线程写入文件的位置
file.seek(mConfigEntity.START_LOCATION); file.seek(mConfigEntity.START_LOCATION);
byte[] buffer = new byte[mBufSize]; byte[] buffer = new byte[mBufSize];
@ -121,10 +119,6 @@ final class SingleThreadTask implements Runnable {
file.write(buffer, 0, len); file.write(buffer, 0, len);
progress(len); progress(len);
} }
file.close();
//close 为阻塞的,需要使用线程池来处理
is.close();
conn.disconnect();
if (CONSTANCE.isCancel) { if (CONSTANCE.isCancel) {
return; return;
} }
@ -133,7 +127,7 @@ final class SingleThreadTask implements Runnable {
return; return;
} }
//支持断点的处理 //支持断点的处理
if (mConfigEntity.isSupportBreakpoint) { if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
Log.i(TAG, "任务【" Log.i(TAG, "任务【"
+ mConfigEntity.TEMP_FILE.getName() + mConfigEntity.TEMP_FILE.getName()
+ "】线程__" + "】线程__"
@ -161,6 +155,20 @@ final class SingleThreadTask implements Runnable {
failDownload(mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e); failDownload(mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e);
} catch (Exception e) { } catch (Exception e) {
failDownload(mChildCurrentLocation, "获取流失败", e); failDownload(mChildCurrentLocation, "获取流失败", e);
} finally {
try {
if (file != null) {
file.close();
}
if (is != null) {
is.close();
}
if (conn != null) {
conn.disconnect();
}
} catch (IOException e) {
e.printStackTrace();
}
} }
} }
@ -170,7 +178,7 @@ final class SingleThreadTask implements Runnable {
protected void stop() { protected void stop() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
if (mConfigEntity.isSupportBreakpoint) { if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
CONSTANCE.STOP_NUM++; CONSTANCE.STOP_NUM++;
Log.d(TAG, "任务【" Log.d(TAG, "任务【"
+ mConfigEntity.TEMP_FILE.getName() + mConfigEntity.TEMP_FILE.getName()
@ -202,7 +210,6 @@ final class SingleThreadTask implements Runnable {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
mChildCurrentLocation += len; mChildCurrentLocation += len;
CONSTANCE.CURRENT_LOCATION += len; CONSTANCE.CURRENT_LOCATION += len;
mListener.onProgress(CONSTANCE.CURRENT_LOCATION);
} }
} }
@ -211,7 +218,7 @@ final class SingleThreadTask implements Runnable {
*/ */
protected void cancel() { protected void cancel() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (mConfigEntity.isSupportBreakpoint) { if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
CONSTANCE.CANCEL_NUM++; CONSTANCE.CANCEL_NUM++;
Log.d(TAG, "任务【" Log.d(TAG, "任务【"
+ mConfigEntity.TEMP_FILE.getName() + mConfigEntity.TEMP_FILE.getName()
@ -250,7 +257,7 @@ final class SingleThreadTask implements Runnable {
if (ex != null) { if (ex != null) {
Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex)); Log.e(TAG, msg + "\n" + CommonUtil.getPrintException(ex));
} }
if (mConfigEntity.isSupportBreakpoint) { if (mConfigEntity.IS_SUPPORT_BREAK_POINT) {
writeConfig(false, currentLocation); writeConfig(false, currentLocation);
if (CONSTANCE.isFail()) { if (CONSTANCE.isFail()) {
Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败"); Log.e(TAG, "任务【" + mConfigEntity.TEMP_FILE.getName() + "】下载失败");

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.download; package com.arialyy.aria.core.download.downloader;
/** /**
* Created by lyy on 2017/1/18. * Created by lyy on 2017/1/18.
* 下载状态常量 * 下载状态常量
*/ */
final class DownloadStateConstance { final class StateConstance {
int CANCEL_NUM = 0; int CANCEL_NUM = 0;
int STOP_NUM = 0; int STOP_NUM = 0;
int FAIL_NUM = 0; int FAIL_NUM = 0;
@ -32,7 +32,7 @@ final class DownloadStateConstance {
boolean isCancel = false; boolean isCancel = false;
boolean isStop = false; boolean isStop = false;
DownloadStateConstance() { StateConstance() {
} }
void cleanState() { void cleanState() {
@ -45,10 +45,6 @@ final class DownloadStateConstance {
FAIL_NUM = 0; FAIL_NUM = 0;
} }
void setThreadNum(int threadNum) {
THREAD_NUM = threadNum;
}
/** /**
* 所有子线程是否都已经停止下载 * 所有子线程是否都已经停止下载
*/ */

@ -21,7 +21,7 @@ import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.orm.Ignore;
/** /**
* Created by AriaL on 2017/6/3. * Created by AriaL on 2017/6/29.
*/ */
public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable { public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable {
/** /**
@ -31,11 +31,12 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
/** /**
* 单位转换后的速度 * 单位转换后的速度
*/ */
@Ignore private String convertSpeed = "0b/s"; @Ignore private String convertSpeed = "";
/** /**
* 下载失败计数每次开始都重置为0 * 下载失败计数每次开始都重置为0
*/ */
@Ignore private int failNum = 0; @Ignore private int failNum = 0;
/** /**
* 扩展字段 * 扩展字段
*/ */
@ -44,6 +45,11 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
* 文件大小 * 文件大小
*/ */
private long fileSize = 1; private long fileSize = 1;
/**
* 转换后的文件大小
*/
private String convertFileSize = "";
private int state = STATE_WAIT; private int state = STATE_WAIT;
/** /**
* 当前下载进度 * 当前下载进度
@ -53,25 +59,23 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
* 完成时间 * 完成时间
*/ */
private long completeTime; private long completeTime;
/**
* 文件名
*/
private String fileName = "";
public long getSpeed() { private boolean isComplete = false;
return speed;
public boolean isComplete() {
return isComplete;
} }
public void setSpeed(long speed) { public void setComplete(boolean complete) {
this.speed = speed; isComplete = complete;
} }
public String getConvertSpeed() { public String getConvertFileSize() {
return convertSpeed; return convertFileSize;
} }
public void setConvertSpeed(String convertSpeed) { public void setConvertFileSize(String convertFileSize) {
this.convertSpeed = convertSpeed; this.convertFileSize = convertFileSize;
} }
public int getFailNum() { public int getFailNum() {
@ -82,6 +86,22 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
this.failNum = failNum; this.failNum = failNum;
} }
public long getSpeed() {
return speed;
}
public void setSpeed(long speed) {
this.speed = speed;
}
public String getConvertSpeed() {
return convertSpeed;
}
public void setConvertSpeed(String convertSpeed) {
this.convertSpeed = convertSpeed;
}
public String getStr() { public String getStr() {
return str; return str;
} }
@ -122,13 +142,10 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
this.completeTime = completeTime; this.completeTime = completeTime;
} }
public String getFileName() { /**
return fileName; * 实体唯一标识符
} */
public abstract String getKey();
public void setFileName(String fileName) {
this.fileName = fileName;
}
public AbsEntity() { public AbsEntity() {
} }
@ -143,10 +160,11 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
dest.writeInt(this.failNum); dest.writeInt(this.failNum);
dest.writeString(this.str); dest.writeString(this.str);
dest.writeLong(this.fileSize); dest.writeLong(this.fileSize);
dest.writeString(this.convertFileSize);
dest.writeInt(this.state); dest.writeInt(this.state);
dest.writeLong(this.currentProgress); dest.writeLong(this.currentProgress);
dest.writeLong(this.completeTime); dest.writeLong(this.completeTime);
dest.writeString(this.fileName); dest.writeByte(this.isComplete ? (byte) 1 : (byte) 0);
} }
protected AbsEntity(Parcel in) { protected AbsEntity(Parcel in) {
@ -155,9 +173,10 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
this.failNum = in.readInt(); this.failNum = in.readInt();
this.str = in.readString(); this.str = in.readString();
this.fileSize = in.readLong(); this.fileSize = in.readLong();
this.convertFileSize = in.readString();
this.state = in.readInt(); this.state = in.readInt();
this.currentProgress = in.readLong(); this.currentProgress = in.readLong();
this.completeTime = in.readLong(); this.completeTime = in.readLong();
this.fileName = in.readString(); this.isComplete = in.readByte() != 0;
} }
} }

@ -0,0 +1,70 @@
/*
* 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.inf;
import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.orm.Primary;
/**
* Created by AriaL on 2017/6/3.
*/
public abstract class AbsGroupEntity extends AbsEntity implements Parcelable {
/**
* 组名组名为任务地址相加的urlMd5
*/
@Primary protected String groupName = "";
/**
* 任务组别名
*/
private String alias = "";
public String getGroupName() {
return groupName;
}
public String getAlias() {
return alias;
}
@Override public String getKey() {
return groupName;
}
public void setAlias(String alias) {
this.alias = alias;
}
public AbsGroupEntity() {
}
@Override public int describeContents() {
return 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(this.groupName);
dest.writeString(this.alias);
}
protected AbsGroupEntity(Parcel in) {
super(in);
this.groupName = in.readString();
this.alias = in.readString();
}
}

@ -0,0 +1,26 @@
/*
* 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.inf;
/**
* Created by AriaL on 2017/6/29.
* 任务组超类
*/
public abstract class AbsGroupTarget<TARGET extends AbsGroupTarget, ENTITY extends AbsGroupEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
}

@ -0,0 +1,31 @@
/*
* 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.inf;
/**
* Created by AriaL on 2017/6/29.
*/
public abstract class AbsGroupTask<TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsGroupEntity>
extends AbsTask<ENTITY> {
protected TASK_ENTITY mTaskEntity;
@Override public String getKey() {
return mEntity.getGroupName();
}
}

@ -0,0 +1,73 @@
/*
* 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.inf;
import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore;
/**
* Created by AriaL on 2017/6/3.
*/
public abstract class AbsNormalEntity extends AbsEntity implements Parcelable {
/**
* 文件名
*/
private String fileName = "";
/**
* 是否是任务组里面的下载实体
*/
private boolean isGroupChild = false;
public boolean isGroupChild() {
return isGroupChild;
}
public void setGroupChild(boolean groupChild) {
isGroupChild = groupChild;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public AbsNormalEntity() {
}
@Override public int describeContents() {
return 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeString(this.fileName);
dest.writeByte(this.isGroupChild ? (byte) 1 : (byte) 0);
}
protected AbsNormalEntity(Parcel in) {
super(in);
this.fileName = in.readString();
this.isGroupChild = in.readByte() != 0;
}
}

@ -0,0 +1,106 @@
/*
* 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.inf;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.util.CommonUtil;
/**
* Created by lyy on 2017/2/28.
*/
public abstract class AbsNormalTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
extends AbsTarget<TARGET, ENTITY, TASK_ENTITY> {
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
protected void setHighestPriority() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(
CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_HIGHEST_PRIORITY))
.exe();
}
/**
* 重定向后新url的key默认为location
*/
protected void _setRedirectUrlKey(String redirectUrlKey) {
if (TextUtils.isEmpty(redirectUrlKey)) {
Log.w("AbsNormalTarget", "重定向后,新url的key不能为null");
return;
}
mTaskEntity.redirectUrlKey = redirectUrlKey;
}
/**
* 删除记录
*/
public void removeRecord() {
mEntity.deleteData();
}
/**
* 获取任务文件大小
*
* @return 文件大小
*/
public long getFileSize() {
return getSize();
}
/**
* 获取单位转换后的文件大小
*
* @return 文件大小{@code xxx mb}
*/
public String getConvertFileSize() {
return getConvertSize();
}
/**
* 下载任务是否存在
*/
public boolean taskExists() {
return false;
}
/**
* 添加任务
*/
public void add() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CREATE))
.exe();
}
/**
* 重新下载
*/
public void reStart() {
cancel();
start();
}
}

@ -0,0 +1,44 @@
/*
* 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.inf;
/**
* Created by lyy on 2017/6/3.
*/
public abstract class AbsNormalTask<ENTITY extends AbsEntity> extends AbsTask<ENTITY> {
/**
* 暂停任务并让任务处于等待状态
*/
public void stopAndWait() {
}
/**
* 最高优先级命令最高优先级命令有以下属性
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
public void setHighestPriority(boolean isHighestPriority) {
isHeighestTask = isHighestPriority;
}
}

@ -0,0 +1,27 @@
/*
* 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.inf;
/**
* Created by AriaL on 2017/6/27.
*/
public abstract class AbsReceiver<ENTITY extends AbsEntity> implements IReceiver<ENTITY>{
public String targetName;
public Object obj;
}

@ -20,121 +20,72 @@ import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.RequestEnum; import com.arialyy.aria.core.RequestEnum;
import com.arialyy.aria.core.command.AbsCmd; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.command.CmdFactory;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
* Created by lyy on 2017/2/28. * Created by AriaL on 2017/7/3.
*/ */
public abstract class AbsTarget<ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity> { public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
protected ENTITY entity; implements ITarget<TARGET> {
protected TASK_ENTITY taskEntity; protected ENTITY mEntity;
protected String targetName; protected TASK_ENTITY mTaskEntity;
protected String mTargetName;
/** /**
* 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中 * 获取任务进度如果任务存在则返回当前进度
* *
* @param str 扩展数据 * @return 该任务进度
*/
public AbsTarget setExtendField(String str) {
entity.setStr(str);
return this;
}
/**
* 获取存放的扩展字段
* 设置扩展字段{@link #setExtendField(String)}
*/ */
public String getExtendField() { public long getCurrentProgress() {
return entity.getStr(); return mEntity == null ? -1 : mEntity.getCurrentProgress();
} }
/** /**
* 获取任务状态 * 获取任务文件大小
* *
* @return {@link IEntity} * @return 文件大小
*/
public int getTaskState() {
return entity.getState();
}
/**
* 将任务设置为最高优先级任务最高优先级任务有以下特点
* 1在下载队列中有且只有一个最高优先级任务
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务当高优先级任务完成后该队尾任务将自动执行
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/
protected void setHighestPriority() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_HIGHEST_PRIORITY))
.exe();
}
/**
* 重定向后新url的key默认为location
*/ */
protected void _setRedirectUrlKey(String redirectUrlKey) { @Override public long getSize() {
if (TextUtils.isEmpty(redirectUrlKey)) { return mEntity == null ? 0 : mEntity.getFileSize();
Log.w("AbsTarget", "重定向后,新url的key不能为null");
return;
}
taskEntity.redirectUrlKey = redirectUrlKey;
} }
/** /**
* 删除记录 * 获取单位转换后的文件大小
*
* @return 文件大小{@code xxx mb}
*/ */
public void removeRecord() { @Override public String getConvertSize() {
entity.deleteData(); return mEntity == null ? "0b" : CommonUtil.formatFileSize(mEntity.getFileSize());
} }
/** /**
* 获取任务文件大小 * 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中
* *
* @return 文件大小 * @param str 扩展数据
*/ */
public long getFileSize() { public TARGET setExtendField(String str) {
if (entity instanceof DownloadEntity) { mEntity.setStr(str);
DownloadEntity entity = (DownloadEntity) this.entity; return (TARGET) this;
return entity.getFileSize();
} else if (entity instanceof UploadEntity) {
UploadEntity entity = (UploadEntity) this.entity;
return entity.getFileSize();
}
return 0;
} }
/** /**
* 获取单位转换后的文件大小 * 获取存放的扩展字段
* * 设置扩展字段{@link #setExtendField(String)}
* @return 文件大小{@code xxx mb}
*/ */
public String getConvertFileSize() { public String getExtendField() {
if (entity instanceof DownloadEntity) { return mEntity.getStr();
DownloadEntity entity = (DownloadEntity) this.entity;
return CommonUtil.formatFileSize(entity.getFileSize());
} else if (entity instanceof UploadEntity) {
UploadEntity entity = (UploadEntity) this.entity;
return CommonUtil.formatFileSize(entity.getFileSize());
}
return "0b";
} }
/** /**
* 下载任务是否存在 * 获取任务状态
*
* @return {@link IEntity}
*/ */
public boolean taskExists() { public int getTaskState() {
return false; return mEntity.getState();
} }
/** /**
@ -142,24 +93,15 @@ public abstract class AbsTarget<ENTITY extends AbsEntity, TASK_ENTITY extends Ab
* *
* @return 返回任务进度 * @return 返回任务进度
*/ */
protected int getPercent() { @Override public int getPercent() {
if (mEntity == null) {
Log.e("AbsTarget", "下载管理器中没有该任务");
return 0; return 0;
} }
if (mEntity.getFileSize() != 0) {
/** return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize());
* 获取任务进度如果任务存在则返回当前进度
*
* @return 该任务进度
*/
public long getCurrentProgress() {
if (entity instanceof DownloadEntity) {
DownloadEntity entity = (DownloadEntity) this.entity;
return entity.getCurrentProgress();
} else if (entity instanceof UploadEntity) {
UploadEntity entity = (UploadEntity) this.entity;
return entity.getCurrentProgress();
} }
return -1; return 0;
} }
/** /**
@ -168,20 +110,22 @@ public abstract class AbsTarget<ENTITY extends AbsEntity, TASK_ENTITY extends Ab
* @param key 头部key * @param key 头部key
* @param header 头部value * @param header 头部value
*/ */
protected void _addHeader(@NonNull String key, @NonNull String header) { public TARGET addHeader(@NonNull String key, @NonNull String header) {
taskEntity.headers.put(key, header); mTaskEntity.headers.put(key, header);
return (TARGET) this;
} }
/** /**
* 给url请求添加头部 * 给url请求添加头部
*/ */
protected void _addHeaders(Map<String, String> headers) { public TARGET addHeaders(Map<String, String> headers) {
if (headers != null && headers.size() > 0) { if (headers != null && headers.size() > 0) {
Set<String> keys = headers.keySet(); Set<String> keys = headers.keySet();
for (String key : keys) { for (String key : keys) {
taskEntity.headers.put(key, headers.get(key)); mTaskEntity.headers.put(key, headers.get(key));
} }
} }
return (TARGET) this;
} }
/** /**
@ -189,62 +133,76 @@ public abstract class AbsTarget<ENTITY extends AbsEntity, TASK_ENTITY extends Ab
* *
* @param requestEnum {@link RequestEnum} * @param requestEnum {@link RequestEnum}
*/ */
protected void _setRequestMode(RequestEnum requestEnum) { public TARGET setRequestMode(RequestEnum requestEnum) {
taskEntity.requestEnum = requestEnum; mTaskEntity.requestEnum = requestEnum;
return (TARGET) this;
} }
/** /**
* 添加任务 * 开始下载
*/ */
public void add() { @Override public void start() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CREATE)) .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.exe(); .exe();
} }
/** /**
* 开始下载 * 停止下载
*
* @see #stop()
*/ */
public void start() { @Deprecated public void pause() {
List<AbsCmd> cmds = new ArrayList<>(); stop();
cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CREATE));
cmds.add(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START));
AriaManager.getInstance(AriaManager.APP).setCmds(cmds).exe();
cmds.clear();
} }
/** @Override public void stop() {
* 停止下载
*/
protected void pause() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_STOP)) .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
.exe(); .exe();
} }
/** /**
* 恢复下载 * 恢复下载
*/ */
protected void resume() { @Override public void resume() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START)) .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.exe(); .exe();
} }
/** /**
* 取消下载 * 取消下载
*/ */
public void cancel() { @Override public void cancel() {
AriaManager.getInstance(AriaManager.APP) AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CANCEL)) .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
.exe(); .exe();
} }
/** /**
* 重新下载 * 创建文件名如果url链接有后缀名则使用url中的后缀名
*
* @return url hashKey
*/ */
void reStart() { protected String createFileName(String url) {
cancel(); int end = url.indexOf("?");
start(); String tempUrl, fileName = "";
if (end > 0) {
tempUrl = url.substring(0, end);
int tempEnd = tempUrl.lastIndexOf("/");
if (tempEnd > 0) {
fileName = tempUrl.substring(tempEnd + 1, tempUrl.length());
}
} else {
int tempEnd = url.lastIndexOf("/");
if (tempEnd > 0) {
fileName = url.substring(tempEnd + 1, url.length());
}
}
if (TextUtils.isEmpty(fileName)) {
fileName = CommonUtil.keyToHashKey(url);
}
return fileName;
} }
} }

@ -16,84 +16,70 @@
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import android.content.Context; import android.content.Context;
import android.os.Handler;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
/** /**
* Created by lyy on 2017/6/3. * Created by AriaL on 2017/6/29.
*/ */
public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsEntity> public abstract class AbsTask<ENTITY extends AbsEntity> implements ITask<ENTITY> {
implements ITask<ENTITY> {
protected ENTITY mEntity; protected ENTITY mEntity;
protected Handler mOutHandler;
/** /**
* 用于生成该任务对象的hash码 * 用于生成该任务对象的hash码
*/ */
private String mTargetName; private String mTargetName;
protected Context mContext; protected Context mContext;
private boolean isHeighestTask = false;
@Override public void stopAndWait() { protected boolean isHeighestTask = false;
/**
* 任务是否完成
*
* @return {@code true} 已经完成{@code false} 未完成
*/
public boolean isComplete() {
return mEntity.isComplete();
} }
/** /**
* @return 返回原始byte速度需要你在配置文件中配置 * 获取当前下载进度
* <pre>
* {@code
* <xml>
* <download>
* ...
* <convertSpeed value="false"/>
* </download>
*
* 或在代码中设置
* Aria.get(this).getDownloadConfig().setConvertSpeed(false);
* </xml>
* }
* </pre>
* 才能生效
*/ */
@Override public long getSpeed() { @Override public long getCurrentProgress() {
return mEntity.getSpeed(); return mEntity.getCurrentProgress();
} }
/** /**
* @return 返回转换单位后的速度需要你在配置文件中配置转换完成后为1b/s1kb/s1mb/s1gb/s1tb/s * 获取单位转换后的进度
* <pre>
* {@code
* <xml>
* <download>
* ...
* <convertSpeed value="true"/>
* </download>
* *
* 或在代码中设置 * @return 已经下载3mb的大小则返回{@code 3mb}
* Aria.get(this).getDownloadConfig().setConvertSpeed(true);
* </xml>
* }
* </pre>
* 才能生效
*/ */
@Override public String getConvertSpeed() { @Override public String getConvertCurrentProgress() {
return mEntity.getConvertSpeed(); if (mEntity.getCurrentProgress() == 0) {
return "0b";
}
return CommonUtil.formatFileSize(mEntity.getCurrentProgress());
} }
/** /**
* 最高优先级命令最高优先级命令有以下属性 * 转换单位后的文件长度
* 1在下载队列中有且只有一个最高优先级任务 *
* 2最高优先级任务会一直存在直到用户手动暂停或任务完成 * @return 如果文件长度为0则返回0m否则返回转换后的长度1b1kb1mb1gb1tb
* 3任务调度器不会暂停最高优先级任务
* 4用户手动暂停或任务完成后第二次重新执行该任务该命令将失效
* 5如果下载队列中已经满了则会停止队尾的任务
* 6把任务设置为最高优先级任务后将自动执行任务不需要重新调用start()启动任务
*/ */
@Override public void setHighestPriority(boolean isHighestPriority) { @Override public String getConvertFileSize() {
isHeighestTask = isHighestPriority; if (mEntity.getFileSize() == 0) {
return "0mb";
}
return CommonUtil.formatFileSize(mEntity.getFileSize());
} }
@Override public boolean isHighestPriorityTask() { /**
return isHeighestTask; * 获取文件大小
*/
@Override public long getFileSize() {
return mEntity.getFileSize();
} }
/** /**
@ -109,54 +95,69 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity, ENTITY extends
} }
/** /**
* 获取文件大小 * 任务当前状态
*
* @return {@link IEntity}
*/ */
@Override public long getFileSize() { public int getState() {
return mEntity.getFileSize(); return mEntity == null ? IEntity.STATE_OTHER : mEntity.getState();
} }
/** /**
* 转换单位后的文件长度 * 获取保存的扩展字段
* *
* @return 如果文件长度为0则返回0m否则返回转换后的长度1b1kb1mb1gb1tb * @return 如果实体不存在则返回null否则返回扩展字段
*/ */
@Override public String getConvertFileSize() { @Override public String getExtendField() {
if (mEntity.getFileSize() == 0) { return mEntity == null ? null : mEntity.getStr();
return "0mb";
}
return CommonUtil.formatFileSize(mEntity.getFileSize());
} }
/** /**
* 获取当前下载进度 * @return 返回原始byte速度需要你在配置文件中配置
* <pre>
* {@code
* <xml>
* <download>
* ...
* <convertSpeed value="false"/>
* </download>
*
* 或在代码中设置
* Aria.get(this).getDownloadConfig().setConvertSpeed(false);
* </xml>
* }
* </pre>
* 才能生效
*/ */
@Override public long getCurrentProgress() { @Override public long getSpeed() {
return mEntity.getCurrentProgress(); return mEntity.getSpeed();
} }
/** /**
* 获取单位转换后的进度 * @return 返回转换单位后的速度需要你在配置文件中配置转换完成后为1b/s1kb/s1mb/s1gb/s1tb/s
* <pre>
* {@code
* <xml>
* <download>
* ...
* <convertSpeed value="true"/>
* </download>
* *
* @return 已经下载3mb的大小则返回{@code 3mb} * 或在代码中设置
* Aria.get(this).getDownloadConfig().setConvertSpeed(true);
* </xml>
* }
* </pre>
* 才能生效
*/ */
@Override public String getConvertCurrentProgress() { @Override public String getConvertSpeed() {
if (mEntity.getCurrentProgress() == 0) { return mEntity.getConvertSpeed();
return "0b";
}
return CommonUtil.formatFileSize(mEntity.getCurrentProgress());
} }
@Override public ENTITY getEntity() { @Override public ENTITY getEntity() {
return mEntity; return mEntity;
} }
/**
* 删除任务记录删除后再次启动该任务的下载时将重新下载
*/
@Override public void removeRecord() {
mEntity.deleteData();
}
public String getTargetName() { public String getTargetName() {
return mTargetName; return mTargetName;
} }
@ -164,4 +165,8 @@ public abstract class AbsTask<TASK_ENTITY extends AbsTaskEntity, ENTITY extends
@Override public void setTargetName(String targetName) { @Override public void setTargetName(String targetName) {
this.mTargetName = targetName; this.mTargetName = targetName;
} }
public boolean isHighestPriorityTask() {
return isHeighestTask;
}
} }

@ -16,14 +16,22 @@
package com.arialyy.aria.core.inf; package com.arialyy.aria.core.inf;
import com.arialyy.aria.core.RequestEnum; import com.arialyy.aria.core.RequestEnum;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.orm.Ignore;
import com.arialyy.aria.orm.Primary;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
*/ */
public abstract class AbsTaskEntity<ENTITY extends AbsEntity> extends DbEntity {
/**
* Task实体对应的key
*/
@Primary public String key = "";
public abstract class AbsTaskEntity {
/** /**
* http 请求头 * http 请求头
*/ */
@ -35,9 +43,45 @@ public abstract class AbsTaskEntity {
public RequestEnum requestEnum = RequestEnum.GET; public RequestEnum requestEnum = RequestEnum.GET;
/** /**
* 重定向后新url的key * 从链接中含有的文件md5码信息所需要的key
*/
public String md5Key = "Content-MD5";
/**
* 从链接中获取文件描述信息所需要的key
*/
public String dispositionKey = "Content-Disposition";
/**
* 重定向后从链接中获取新url所需要的key
*/ */
public String redirectUrlKey = "location"; public String redirectUrlKey = "location";
public abstract AbsEntity getEntity(); /**
* 从Disposition获取的文件名说需要的key
*/
public String dispositionFileKey = "attachment;filename";
/**
* 重定向链接
*/
public String redirectUrl = "";
/**
* {@code true} 删除任务数据库记录并且删除已经下载完成的文件
* {@code false} 如果任务已经完成只删除任务数据库记录
*/
@Ignore public boolean removeFile = false;
/**
* 是否支持断点, {@code true} 为支持断点
*/
public boolean isSupportBP = true;
/**
* 状态码
*/
public int code;
public abstract ENTITY getEntity();
} }

@ -20,42 +20,41 @@ import com.arialyy.aria.orm.Ignore;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
*/ */
public interface IEntity { public interface IEntity {
/** /**
* 其它状态 * 其它状态
*/ */
@Ignore public static final int STATE_OTHER = -1; @Ignore int STATE_OTHER = -1;
/** /**
* 失败状态 * 失败状态
*/ */
@Ignore public static final int STATE_FAIL = 0; @Ignore int STATE_FAIL = 0;
/** /**
* 完成状态 * 完成状态
*/ */
@Ignore public static final int STATE_COMPLETE = 1; @Ignore int STATE_COMPLETE = 1;
/** /**
* 停止状态 * 停止状态
*/ */
@Ignore public static final int STATE_STOP = 2; @Ignore int STATE_STOP = 2;
/** /**
* 未开始状态 * 等待状态
*/ */
@Ignore public static final int STATE_WAIT = 3; @Ignore int STATE_WAIT = 3;
/** /**
* 下载中 * 下载中
*/ */
@Ignore public static final int STATE_RUNNING = 4; @Ignore int STATE_RUNNING = 4;
/** /**
* 预处理 * 预处理
*/ */
@Ignore public static final int STATE_PRE = 5; @Ignore int STATE_PRE = 5;
/** /**
* 预处理完成 * 预处理完成
*/ */
@Ignore public static final int STATE_POST_PRE = 6; @Ignore int STATE_POST_PRE = 6;
/** /**
* 取消下载 * 取消下载
*/ */
@Ignore public static final int STATE_CANCEL = 7; @Ignore int STATE_CANCEL = 7;
} }

@ -13,73 +13,56 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package com.arialyy.aria.core.inf;
package com.arialyy.aria.core.download;
/** /**
* 下载监听 * Created by Aria.Lao on 2017/7/18.
*/ * 基础事件
interface IDownloadListener {
/**
* 支持断点回调
*
* @param support true,支持false 不支持
*/
public void supportBreakpoint(boolean support);
/**
* 取消下载
*/
public void onCancel();
/**
* 下载失败
*/ */
public void onFail(); public interface IEventListener {
/** /**
* 预处理有时有些地址链接比较慢这时可以先在这个地方出来一些界面上的UI如按钮的状态 * 预处理有时有些地址链接比较慢这时可以先在这个地方出来一些界面上的UI如按钮的状态
*/ */
public void onPre(); void onPre();
/** /**
* 预处理完成,准备下载---开始下载之间 * 预处理完成,准备下载---开始下载之间
*/ */
public void onPostPre(long fileSize); void onPostPre(long fileSize);
/** /**
* 下载监听 * 开始
*/ */
public void onProgress(long currentLocation); void onStart(long startLocation);
/** /**
* 单一线程的结束位置 * 恢复位置
*/ */
public void onChildComplete(long finishLocation); void onResume(long resumeLocation);
/** /**
* 开始 * 下载监听
*/ */
public void onStart(long startLocation); void onProgress(long currentLocation);
/** /**
* 子程恢复下载的位置 * 停止
*/ */
public void onChildResume(long resumeLocation); void onStop(long stopLocation);
/** /**
* 恢复位置 * 下载完成
*/ */
public void onResume(long resumeLocation); void onComplete();
/** /**
* 停止 * 取消下载
*/ */
public void onStop(long stopLocation); void onCancel();
/** /**
* 下载完成 * 下载失败
*/ */
public void onComplete(); void onFail();
} }

@ -44,7 +44,7 @@ public interface IReceiver<ENTITY extends IEntity> {
/** /**
* 删除所有任务 * 删除所有任务
*/ */
public void removeAllTask(); public void removeAllTask(boolean removeFile);
/** /**
* 任务是否存在 * 任务是否存在
@ -56,5 +56,5 @@ public interface IReceiver<ENTITY extends IEntity> {
/** /**
* 获取任务列表 * 获取任务列表
*/ */
public List<ENTITY> getTaskList(); public List<ENTITY> getSimpleTaskList();
} }

@ -0,0 +1,86 @@
/*
* 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.inf;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.RequestEnum;
import java.util.Map;
/**
* Created by AriaL on 2017/6/29.
*/
public interface ITarget<TARGET extends ITarget> {
/**
* 任务文件大小
*/
long getSize();
/**
* 转换后的大小
*/
String getConvertSize();
/**
* 获取任务进度百分比
*/
int getPercent();
/**
* 获取任务进度如果任务存在则返回当前进度
*/
long getCurrentProgress();
/**
* 给url请求添加头部
*
* @param key 头部key
* @param header 头部value
*/
TARGET addHeader(@NonNull String key, @NonNull String header) ;
/**
* 给url请求添加头部
*/
TARGET addHeaders(Map<String, String> headers);
/**
* 设置请求类型
*
* @param requestEnum {@link RequestEnum}
*/
TARGET setRequestMode(RequestEnum requestEnum);
/**
* 开始下载
*/
void start();
/**
* 停止下载
*/
void stop();
/**
* 恢复下载
*/
void resume();
/**
* 取消下载
*/
void cancel();
}

@ -18,25 +18,17 @@ package com.arialyy.aria.core.inf;
/** /**
* Created by lyy on 2017/2/13. * Created by lyy on 2017/2/13.
*/ */
public interface ITask<ENTITY extends AbsEntity> { public interface ITask<ENTITY extends AbsEntity> {
/** /**
* 暂停任务并让任务处于等待状态 * 获取下载状态
*/ */
public void stopAndWait(); int getState();
/** /**
* 设置任务为最高优先级任务在下载队列中有且只有一个最高优先级任务 * 获取扩展字段
*/
public void setHighestPriority(boolean isHighestPriority);
/**
* 该任务是否是最高优先级任务
*
* @return {@code true} 任务为最高优先级任务
*/ */
public boolean isHighestPriorityTask(); String getExtendField();
/** /**
* 唯一标识符DownloadTask 为下载地址UploadTask 为文件路径 * 唯一标识符DownloadTask 为下载地址UploadTask 为文件路径
@ -44,14 +36,14 @@ public interface ITask<ENTITY extends AbsEntity> {
public String getKey(); public String getKey();
/** /**
* 是否正执行 * 任务是否正执行
* *
* @return true正在执行 * @return true正在执行
*/ */
public boolean isRunning(); public boolean isRunning();
/** /**
* 获取工具实体 * 获取信息实体
*/ */
public ENTITY getEntity(); public ENTITY getEntity();
@ -100,5 +92,4 @@ public interface ITask<ENTITY extends AbsEntity> {
public void setTargetName(String targetName); public void setTargetName(String targetName);
public void removeRecord();
} }

@ -17,24 +17,51 @@
package com.arialyy.aria.core.queue; package com.arialyy.aria.core.queue;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.pool.CachePool; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.pool.ExecutePool; import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import java.util.Set; import java.util.Set;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
* 任务队列 * 任务队列
*/ */
abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsEntity> abstract class AbsTaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsEntity>
implements ITaskQueue<TASK, TASK_ENTITY, ENTITY> { implements ITaskQueue<TASK, TASK_ENTITY, ENTITY> {
private final String TAG = "AbsTaskQueue"; private final String TAG = "AbsTaskQueue";
CachePool<TASK> mCachePool = new CachePool<>(); BaseCachePool<TASK> mCachePool;
ExecutePool<TASK> mExecutePool; BaseExecutePool<TASK> mExecutePool;
AbsTaskQueue() {
mCachePool = setCachePool();
mExecutePool = setExecutePool();
}
abstract BaseCachePool<TASK> setCachePool();
abstract BaseExecutePool<TASK> setExecutePool();
@Override public boolean taskIsRunning(String key) {
return mExecutePool.getTask(key) != null;
}
@Override public void removeAllTask() {
Set<String> exeKeys = mExecutePool.getAllTask().keySet();
for (String key : exeKeys) {
TASK task = mExecutePool.getAllTask().get(key);
if (task != null) task.cancel();
}
Set<String> cacheKeys = mCachePool.getAllTask().keySet();
for (String key : cacheKeys) {
mExecutePool.removeTask(key);
}
}
/** /**
* 停止所有任务 * 停止所有任务
@ -55,17 +82,27 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum(); return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum();
} }
/**
* 获取实体的索引
*/
public abstract String getKey(ENTITY entity);
/**
* 获取配置文件配置的最大可执行任务数
*/
public abstract int getConfigMaxNum();
/** /**
* 获取任务执行池 * 获取任务执行池
*/ */
public ExecutePool getExecutePool() { public BaseExecutePool getExecutePool() {
return mExecutePool; return mExecutePool;
} }
/** /**
* 获取缓存池 * 获取缓存池
*/ */
public CachePool getCachePool() { public BaseCachePool getCachePool() {
return mCachePool; return mCachePool;
} }
@ -74,21 +111,44 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
* *
* @return 获取缓存的任务数 * @return 获取缓存的任务数
*/ */
@Override public int cachePoolSize() { @Override public int getCurrentCachePoolNum() {
return mCachePool.size(); return mCachePool.size();
} }
/** /**
* 获取当前运行的任务数 * 获取执行池中的任务数量
* *
* @return 当前正在执行的任务数 * @return 当前正在执行的任务数
*/ */
@Override public int getExeTaskNum() { @Override public int getCurrentExePoolNum() {
return mExecutePool.size(); return mExecutePool.size();
} }
@Override public void setTaskHighestPriority(TASK task) { @Override public void setMaxTaskNum(int downloadNum) {
int oldMaxSize = getConfigMaxNum();
int diff = downloadNum - oldMaxSize;
if (oldMaxSize == downloadNum) {
Log.d(TAG, "设置的下载任务数和配置文件的下载任务数一直,跳过");
return;
}
//设置的任务数小于配置任务数
if (diff <= -1 && mExecutePool.size() >= oldMaxSize) {
for (int i = 0, len = Math.abs(diff); i < len; i++) {
TASK eTask = mExecutePool.pollTask();
if (eTask != null) {
stopTask(eTask);
}
}
}
mExecutePool.setMaxNum(downloadNum);
if (diff >= 1) {
for (int i = 0; i < diff; i++) {
TASK nextTask = getNextTask();
if (nextTask != null && nextTask.getState() == IEntity.STATE_WAIT) {
startTask(nextTask);
}
}
}
} }
@Override public TASK getTask(String url) { @Override public TASK getTask(String url) {
@ -109,12 +169,22 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
@Override public void stopTask(TASK task) { @Override public void stopTask(TASK task) {
if (!task.isRunning()) Log.w(TAG, "停止任务失败,【任务已经停止】"); if (!task.isRunning()) Log.w(TAG, "停止任务失败,【任务已经停止】");
task.setHighestPriority(false);
if (mExecutePool.removeTask(task)) { if (mExecutePool.removeTask(task)) {
task.stop(); task.stop();
} else { } else {
task.stop(); task.stop();
Log.w(TAG, "停止任务失败,【任务已经停止】"); Log.w(TAG, "删除任务失败,【执行队列中没有该任务】");
}
}
@Override public void removeTask(ENTITY entity) {
TASK task = mExecutePool.getTask(getKey(entity));
if (task != null) {
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
}
task = mCachePool.getTask(getKey(entity));
if (task != null) {
Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
} }
} }
@ -130,7 +200,11 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
} }
} }
@Override public void cancelTask(TASK task) { @Override public TASK getTask(ENTITY entity) {
return getTask(getKey(entity));
}
@Override public void removeTask(TASK task) {
task.cancel(); task.cancel();
} }

@ -0,0 +1,83 @@
/*
* 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.queue;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.core.queue.pool.DownloadSharePool;
import com.arialyy.aria.core.scheduler.DQueueMapping;
import com.arialyy.aria.core.scheduler.DownloadGroupSchedulers;
/**
* Created by AriaL on 2017/6/29.
* 任务组下载队列
*/
public class DownloadGroupTaskQueue
extends AbsTaskQueue<DownloadGroupTask, DownloadGroupTaskEntity, DownloadGroupEntity> {
private static volatile DownloadGroupTaskQueue INSTANCE = null;
private final String TAG = "DownloadGroupTaskQueue";
public static DownloadGroupTaskQueue getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new DownloadGroupTaskQueue();
}
}
return INSTANCE;
}
private DownloadGroupTaskQueue() {
}
@Override BaseCachePool<DownloadGroupTask> setCachePool() {
return DownloadSharePool.getInstance().cachePool;
}
@Override BaseExecutePool<DownloadGroupTask> setExecutePool() {
return DownloadSharePool.getInstance().executePool;
}
@Override public DownloadGroupTask createTask(String targetName, DownloadGroupTaskEntity entity) {
DownloadGroupTask task = null;
if (!TextUtils.isEmpty(targetName)) {
task = (DownloadGroupTask) TaskFactory.getInstance()
.createTask(targetName, entity, DownloadGroupSchedulers.getInstance());
entity.key = entity.getEntity().getGroupName();
mCachePool.putTask(task);
DQueueMapping.getInstance().addType(task.getKey(), DQueueMapping.QUEUE_TYPE_DOWNLOAD_GROUP);
} else {
Log.e(TAG, "target name 为 null!!");
}
return task;
}
@Override public String getKey(DownloadGroupEntity entity) {
return entity.getGroupName();
}
@Override public int getConfigMaxNum() {
return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().oldMaxTaskNum;
}
}

@ -22,8 +22,10 @@ import com.arialyy.aria.core.AriaManager;
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 com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.ExecutePool; import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.core.queue.pool.DownloadSharePool;
import com.arialyy.aria.core.scheduler.DQueueMapping;
import com.arialyy.aria.core.scheduler.DownloadSchedulers; import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Map; import java.util.Map;
@ -48,10 +50,28 @@ public class DownloadTaskQueue
} }
private DownloadTaskQueue() { private DownloadTaskQueue() {
mExecutePool = new ExecutePool<>(true);
} }
@Override public void setTaskHighestPriority(DownloadTask task) { @Override BaseCachePool<DownloadTask> setCachePool() {
return DownloadSharePool.getInstance().cachePool;
}
@Override BaseExecutePool<DownloadTask> setExecutePool() {
return DownloadSharePool.getInstance().executePool;
}
@Override public String getKey(DownloadEntity entity) {
return entity.getDownloadUrl();
}
@Override public int getConfigMaxNum() {
return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().oldMaxTaskNum;
}
/**
* 设置任务为最高优先级任务
*/
public void setTaskHighestPriority(DownloadTask task) {
task.setHighestPriority(true); task.setHighestPriority(true);
Map<String, DownloadTask> exeTasks = mExecutePool.getAllTask(); Map<String, DownloadTask> exeTasks = mExecutePool.getAllTask();
if (exeTasks != null && !exeTasks.isEmpty()) { if (exeTasks != null && !exeTasks.isEmpty()) {
@ -91,66 +111,36 @@ public class DownloadTaskQueue
} }
} }
public void setMaxSpeed(double maxSpeed){ /**
* 最大下载速度
*/
public void setMaxSpeed(double maxSpeed) {
Map<String, DownloadTask> tasks = mExecutePool.getAllTask(); Map<String, DownloadTask> tasks = mExecutePool.getAllTask();
Set<String> keys = tasks.keySet(); Set<String> keys = tasks.keySet();
for (String key : keys){ for (String key : keys) {
DownloadTask task = tasks.get(key); DownloadTask task = tasks.get(key);
task.setMaxSpeed(maxSpeed); task.setMaxSpeed(maxSpeed);
} }
} }
@Override public void setMaxTaskNum(int downloadNum) {
int oldMaxSize = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().oldMaxTaskNum;
int diff = downloadNum - oldMaxSize;
if (oldMaxSize == downloadNum) {
Log.d(TAG, "设置的下载任务数和配置文件的下载任务数一直,跳过");
return;
}
//设置的任务数小于配置任务数
if (diff <= -1 && mExecutePool.size() >= oldMaxSize) {
for (int i = 0, len = Math.abs(diff); i < len; i++) {
DownloadTask eTask = mExecutePool.pollTask();
if (eTask != null) {
stopTask(eTask);
}
}
}
mExecutePool.setDownloadNum(downloadNum);
if (diff >= 1) {
for (int i = 0; i < diff; i++) {
DownloadTask nextTask = getNextTask();
if (nextTask != null && nextTask.getDownloadEntity().getState() == IEntity.STATE_WAIT) {
startTask(nextTask);
}
}
}
}
@Override public DownloadTask createTask(String target, DownloadTaskEntity entity) { @Override public DownloadTask createTask(String target, DownloadTaskEntity entity) {
DownloadTask task = null; DownloadTask task = null;
if (!TextUtils.isEmpty(target)) { if (!TextUtils.isEmpty(target)) {
task = (DownloadTask) TaskFactory.getInstance() task = (DownloadTask) TaskFactory.getInstance()
.createTask(target, entity, DownloadSchedulers.getInstance()); .createTask(target, entity, DownloadSchedulers.getInstance());
entity.key = entity.getEntity().getDownloadPath();
mCachePool.putTask(task); mCachePool.putTask(task);
DQueueMapping.getInstance().addType(task.getKey(), DQueueMapping.QUEUE_TYPE_DOWNLOAD);
} else { } else {
Log.e(TAG, "target name 为 null是!!"); Log.e(TAG, "target name 为 null!!");
}
return task;
} }
@Override public DownloadTask getTask(DownloadEntity entity) { return task;
return getTask(entity.getDownloadUrl());
} }
@Override public void removeTask(DownloadEntity entity) { @Override public void stopTask(DownloadTask task) {
DownloadTask task = mExecutePool.getTask(entity.getDownloadUrl()); task.setHighestPriority(false);
if (task != null) { super.stopTask(task);
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
}
task = mCachePool.getTask(entity.getDownloadUrl());
if (task != null) {
Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
}
} }
} }

@ -19,8 +19,10 @@ package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
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;
@ -30,7 +32,15 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
* Created by lyy on 2016/8/16. * Created by lyy on 2016/8/16.
* 任务功能接口 * 任务功能接口
*/ */
public interface ITaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntity, ENTITY extends IEntity> { public interface ITaskQueue<TASK extends AbsTask, TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsEntity> {
/**
* 通过key判断任务是否正在执行
*
* @param key 下载链接或上传文件的路径
* @return {@code true} 任务正在运行
*/
boolean taskIsRunning(String key);
/** /**
* 停止所有任务 * 停止所有任务
@ -38,11 +48,9 @@ public interface ITaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
void stopAllTask(); void stopAllTask();
/** /**
* 设置任务为最高优先级任务 * 删除所有任务
*
* @param task {@link DownloadTask}{@link UploadTask}
*/ */
void setTaskHighestPriority(TASK task); void removeAllTask();
/** /**
* 开始任务 * 开始任务
@ -59,11 +67,18 @@ public interface ITaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
void stopTask(TASK task); void stopTask(TASK task);
/** /**
* 取消任务 * 通过任务任务实体删除任务
* *
* @param task {@link DownloadTask}{@link UploadTask} * @param task {@link DownloadTask}{@link UploadTask}
*/ */
void cancelTask(TASK task); void removeTask(TASK task);
/**
* 通过工作实体删除任务
*
* @param entity 工作实体{@link DownloadEntity}{@link UploadEntity}
*/
void removeTask(ENTITY entity);
/** /**
* 重试下载 * 重试下载
@ -73,24 +88,24 @@ public interface ITaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
void reTryStart(TASK task); void reTryStart(TASK task);
/** /**
* 获取正在执行的任务数量 * 获取当前执行池中的任务数量
*/ */
int getExeTaskNum(); int getCurrentExePoolNum();
/** /**
* 任务缓存池大小 * 获取当前任务缓存池中的任务数量
*/ */
int cachePoolSize(); int getCurrentCachePoolNum();
/** /**
* 设置最大任务数 * 设置执行池可执行的最大任务数
* *
* @param newMaxNum 最大任务数 * @param newMaxNum 最大任务数
*/ */
void setMaxTaskNum(int newMaxNum); void setMaxTaskNum(int newMaxNum);
/** /**
* 获取可执行队列的大小 * 获取执行池可执行的最大任务数
*/ */
int getMaxTaskNum(); int getMaxTaskNum();
@ -119,13 +134,6 @@ public interface ITaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
*/ */
TASK getTask(String url); TASK getTask(String url);
/**
* 通过工作实体删除任务
*
* @param entity 工作实体{@link DownloadEntity}{@link UploadEntity}
*/
void removeTask(ENTITY entity);
/** /**
* 获取缓存池的下一个任务 * 获取缓存池的下一个任务
* *

@ -17,12 +17,15 @@
package com.arialyy.aria.core.queue; package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.scheduler.DownloadSchedulers; import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulers; import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.core.scheduler.UploadSchedulers;
import com.arialyy.aria.core.upload.UploadTask; import com.arialyy.aria.core.upload.UploadTask;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
@ -30,8 +33,7 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
* Created by lyy on 2016/8/18. * Created by lyy on 2016/8/18.
* 任务工厂 * 任务工厂
*/ */
public class TaskFactory { class TaskFactory {
private static final String TAG = "TaskFactory";
private static volatile TaskFactory INSTANCE = null; private static volatile TaskFactory INSTANCE = null;
@ -53,20 +55,36 @@ public class TaskFactory {
* *
* @param entity 下载实体 * @param entity 下载实体
* @param schedulers 对应的任务调度器 * @param schedulers 对应的任务调度器
* @param <ENTITY> {@link DownloadTaskEntity}{@link UploadTaskEntity} * @param <TASK_ENTITY> {@link DownloadTaskEntity}{@link UploadTaskEntity}{@link
* @param <SCHEDULER> {@link DownloadSchedulers} * DownloadGroupTaskEntity}
* @return {@link DownloadTask}{@link UploadTask} * @param <SCHEDULER> {@link DownloadSchedulers}{@link UploadSchedulers}
* @return {@link DownloadTask}{@link UploadTask}{@link DownloadGroupTask}
*/ */
<ENTITY extends AbsTaskEntity, SCHEDULER extends ISchedulers> ITask createTask(String targetName, <TASK_ENTITY extends AbsTaskEntity, SCHEDULER extends ISchedulers> ITask createTask(
ENTITY entity, SCHEDULER schedulers) { String targetName, TASK_ENTITY entity, SCHEDULER schedulers) {
if (entity instanceof DownloadTaskEntity) { if (entity instanceof DownloadTaskEntity) {
return createDownloadTask(targetName, (DownloadTaskEntity) entity, schedulers); return createDownloadTask(targetName, (DownloadTaskEntity) entity, schedulers);
} else if (entity instanceof UploadTaskEntity) { } else if (entity instanceof UploadTaskEntity) {
return createUploadTask(targetName, (UploadTaskEntity) entity, schedulers); return createUploadTask(targetName, (UploadTaskEntity) entity, schedulers);
} else if (entity instanceof DownloadGroupTaskEntity) {
return createDownloadGroupTask(targetName, (DownloadGroupTaskEntity) entity, schedulers);
} }
return null; return null;
} }
/**
* 创建下载任务主任务
*
* @param entity 下载任务实体{@link DownloadGroupTask}
* @param schedulers {@link ISchedulers}
*/
private DownloadGroupTask createDownloadGroupTask(String targetName,
DownloadGroupTaskEntity entity, ISchedulers schedulers) {
DownloadGroupTask.Builder builder = new DownloadGroupTask.Builder(targetName, entity);
builder.setOutHandler(schedulers);
return builder.build();
}
/** /**
* @param entity 上传任务实体{@link UploadTaskEntity} * @param entity 上传任务实体{@link UploadTaskEntity}
* @param schedulers {@link ISchedulers} * @param schedulers {@link ISchedulers}

@ -19,7 +19,9 @@ package com.arialyy.aria.core.queue;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.queue.pool.ExecutePool; import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.core.queue.pool.UploadSharePool;
import com.arialyy.aria.core.scheduler.UploadSchedulers; import com.arialyy.aria.core.scheduler.UploadSchedulers;
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;
@ -43,11 +45,22 @@ public class UploadTaskQueue extends AbsTaskQueue<UploadTask, UploadTaskEntity,
} }
private UploadTaskQueue() { private UploadTaskQueue() {
mExecutePool = new ExecutePool<>(false);
} }
@Override public void setMaxTaskNum(int newMaxNum) { @Override BaseCachePool<UploadTask> setCachePool() {
return UploadSharePool.getInstance().cachePool;
}
@Override BaseExecutePool<UploadTask> setExecutePool() {
return UploadSharePool.getInstance().executePool;
}
@Override public String getKey(UploadEntity entity) {
return entity.getFilePath();
}
@Override public int getConfigMaxNum() {
return AriaManager.getInstance(AriaManager.APP).getUploadConfig().oldMaxTaskNum;
} }
@Override public UploadTask createTask(String targetName, UploadTaskEntity entity) { @Override public UploadTask createTask(String targetName, UploadTaskEntity entity) {
@ -55,25 +68,11 @@ public class UploadTaskQueue extends AbsTaskQueue<UploadTask, UploadTaskEntity,
if (!TextUtils.isEmpty(targetName)) { if (!TextUtils.isEmpty(targetName)) {
task = (UploadTask) TaskFactory.getInstance() task = (UploadTask) TaskFactory.getInstance()
.createTask(targetName, entity, UploadSchedulers.getInstance()); .createTask(targetName, entity, UploadSchedulers.getInstance());
entity.key = entity.getEntity().getFilePath();
mCachePool.putTask(task); mCachePool.putTask(task);
} else { } else {
Log.e(TAG, "target name 为 null是!!"); Log.e(TAG, "target name 为 null是!!");
} }
return task; return task;
} }
@Override public UploadTask getTask(UploadEntity entity) {
return getTask(entity.getFilePath());
}
@Override public void removeTask(UploadEntity entity) {
UploadTask task = mExecutePool.getTask(entity.getFilePath());
if (task != null) {
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
}
task = mCachePool.getTask(entity.getFilePath());
if (task != null) {
Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
}
}
} }

@ -19,6 +19,7 @@ package com.arialyy.aria.core.queue.pool;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap; import java.util.HashMap;
@ -32,20 +33,20 @@ import java.util.concurrent.TimeUnit;
* Created by lyy on 2016/8/14. * Created by lyy on 2016/8/14.
* 任务缓存池所有下载任务最先缓存在这个池中 * 任务缓存池所有下载任务最先缓存在这个池中
*/ */
public class CachePool<TASK extends ITask> implements IPool<TASK> { public class BaseCachePool<TASK extends AbsTask> implements IPool<TASK> {
private static final String TAG = "CachePool"; private static final String TAG = "BaseCachePool";
private static final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数 private static final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数
private static final long TIME_OUT = 1000; private static final long TIME_OUT = 1000;
private Map<String, TASK> mCacheMap; private Map<String, TASK> mCacheMap;
private LinkedBlockingQueue<TASK> mCacheQueue; private LinkedBlockingQueue<TASK> mCacheQueue;
public CachePool() { public BaseCachePool() {
mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM); mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM);
mCacheMap = new HashMap<>(); mCacheMap = new HashMap<>();
} }
/** /**
* 获取所有正在执行的任务 * 获取被缓存的任务
*/ */
public Map<String, TASK> getAllTask() { public Map<String, TASK> getAllTask() {
return mCacheMap; return mCacheMap;
@ -95,7 +96,7 @@ public class CachePool<TASK extends ITask> implements IPool<TASK> {
@Override public TASK pollTask() { @Override public TASK pollTask() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
TASK task = null; TASK task;
task = mCacheQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS); task = mCacheQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (task != null) { if (task != null) {
String url = task.getKey(); String url = task.getKey();

@ -19,11 +19,12 @@ package com.arialyy.aria.core.queue.pool;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.scheduler.DQueueMapping;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -31,23 +32,28 @@ import java.util.concurrent.TimeUnit;
* Created by lyy on 2016/8/15. * Created by lyy on 2016/8/15.
* 任务执行池所有当前下载任务都该任务池中默认下载大小为2 * 任务执行池所有当前下载任务都该任务池中默认下载大小为2
*/ */
public class ExecutePool<TASK extends ITask> implements IPool<TASK> { public class BaseExecutePool<TASK extends AbsTask> implements IPool<TASK> {
private static final String TAG = "ExecutePool"; private final String TAG = "BaseExecutePool";
private static final long TIME_OUT = 1000; final long TIME_OUT = 1000;
private ArrayBlockingQueue<TASK> mExecuteQueue; ArrayBlockingQueue<TASK> mExecuteQueue;
private Map<String, TASK> mExecuteMap; Map<String, TASK> mExecuteMap;
private int mSize; int mSize;
public ExecutePool(boolean isDownload) { BaseExecutePool() {
if (isDownload) { mSize = getMaxSize();
mSize = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum();
} else {
mSize = AriaManager.getInstance(AriaManager.APP).getUploadConfig().getMaxTaskNum();
}
mExecuteQueue = new ArrayBlockingQueue<>(mSize); mExecuteQueue = new ArrayBlockingQueue<>(mSize);
mExecuteMap = new HashMap<>(); mExecuteMap = new HashMap<>();
} }
/**
* 获取最大任务数配置
*
* @return {@link AriaManager#getDownloadConfig()} {@link AriaManager#getUploadConfig()}如果不设置默认返回2
*/
protected int getMaxSize() {
return 2;
}
/** /**
* 获取所有正在执行的任务 * 获取所有正在执行的任务
*/ */
@ -67,10 +73,6 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
return false; return false;
} else { } else {
if (mExecuteQueue.size() >= mSize) { if (mExecuteQueue.size() >= mSize) {
Set<String> keys = mExecuteMap.keySet();
for (String key : keys) {
if (mExecuteMap.get(key).isHighestPriorityTask()) return false;
}
if (pollFirstTask()) { if (pollFirstTask()) {
return putNewTask(task); return putNewTask(task);
} }
@ -83,19 +85,19 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
} }
/** /**
* 设置执行任务数 * 设置执行队列最大任务数
* *
* @param downloadNum 下载数 * @param maxNum 下载数
*/ */
public void setDownloadNum(int downloadNum) { public void setMaxNum(int maxNum) {
try { try {
ArrayBlockingQueue<TASK> temp = new ArrayBlockingQueue<>(downloadNum); ArrayBlockingQueue<TASK> temp = new ArrayBlockingQueue<>(maxNum);
TASK task; TASK task;
while ((task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS)) != null) { while ((task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS)) != null) {
temp.offer(task); temp.offer(task);
} }
mExecuteQueue = temp; mExecuteQueue = temp;
mSize = downloadNum; mSize = maxNum;
} catch (InterruptedException e) { } catch (InterruptedException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -104,9 +106,9 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
/** /**
* 添加新任务 * 添加新任务
* *
* @param newTask 下载任务 * @param newTask 新任务
*/ */
private boolean putNewTask(TASK newTask) { boolean putNewTask(TASK newTask) {
String url = newTask.getKey(); String url = newTask.getKey();
boolean s = mExecuteQueue.offer(newTask); boolean s = mExecuteQueue.offer(newTask);
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】")); Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
@ -119,16 +121,13 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
/** /**
* 队列满时将移除下载队列中的第一个任务 * 队列满时将移除下载队列中的第一个任务
*/ */
private boolean pollFirstTask() { boolean pollFirstTask() {
try { try {
TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS); TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) { if (oldTask == null) {
Log.e(TAG, "移除任务失败"); Log.e(TAG, "移除任务失败");
return false; return false;
} }
if (oldTask.isHighestPriorityTask()) {
return false;
}
oldTask.stop(); oldTask.stop();
String key = CommonUtil.keyToHashKey(oldTask.getKey()); String key = CommonUtil.keyToHashKey(oldTask.getKey());
mExecuteMap.remove(key); mExecuteMap.remove(key);
@ -142,7 +141,7 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
@Override public TASK pollTask() { @Override public TASK pollTask() {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
try { try {
TASK task = null; TASK task;
task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS); task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (task != null) { if (task != null) {
String url = task.getKey(); String url = task.getKey();
@ -173,22 +172,22 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
Log.e(TAG, "任务不能为空"); Log.e(TAG, "任务不能为空");
return false; return false;
} else { } else {
String key = CommonUtil.keyToHashKey(task.getKey()); return removeTask(task.getKey());
mExecuteMap.remove(key);
return mExecuteQueue.remove(task);
} }
} }
} }
@Override public boolean removeTask(String downloadUrl) { @Override public boolean removeTask(String key) {
synchronized (AriaManager.LOCK) { synchronized (AriaManager.LOCK) {
if (TextUtils.isEmpty(downloadUrl)) { if (TextUtils.isEmpty(key)) {
Log.e(TAG, "请传入有效的任务key"); Log.e(TAG, "请传入有效的任务key");
return false; return false;
} }
String key = CommonUtil.keyToHashKey(downloadUrl); String convertKey = CommonUtil.keyToHashKey(key);
TASK task = mExecuteMap.get(key); TASK task = mExecuteMap.get(convertKey);
mExecuteMap.remove(key); mExecuteMap.remove(convertKey);
DQueueMapping.getInstance().removeType(key);
return mExecuteQueue.remove(task); return mExecuteQueue.remove(task);
} }
} }

@ -0,0 +1,82 @@
/*
* 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.queue.pool;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.util.CommonUtil;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* Created by AriaL on 2017/6/29.
* 单个下载任务的执行池
*/
public class DownloadExecutePool<TASK extends AbsTask> extends BaseExecutePool<TASK> {
private final String TAG = "DownloadExecutePool";
@Override protected int getMaxSize() {
return AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum();
}
@Override public boolean putTask(TASK task) {
synchronized (AriaManager.LOCK) {
if (task == null) {
Log.e(TAG, "任务不能为空!!");
return false;
}
String url = task.getKey();
if (mExecuteQueue.contains(task)) {
Log.e(TAG, "队列中已经包含了该任务,任务key【" + url + "】");
return false;
} else {
if (mExecuteQueue.size() >= mSize) {
Set<String> keys = mExecuteMap.keySet();
for (String key : keys) {
if (mExecuteMap.get(key).isHighestPriorityTask()) return false;
}
if (pollFirstTask()) {
return putNewTask(task);
}
} else {
return putNewTask(task);
}
}
}
return false;
}
@Override boolean pollFirstTask() {
try {
TASK oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (oldTask == null) {
Log.e(TAG, "移除任务失败");
return false;
}
if (oldTask.isHighestPriorityTask()) {
return false;
}
oldTask.stop();
String key = CommonUtil.keyToHashKey(oldTask.getKey());
mExecuteMap.remove(key);
} catch (InterruptedException e) {
e.printStackTrace();
return false;
}
return true;
}
}

@ -0,0 +1,43 @@
/*
* 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.queue.pool;
import com.arialyy.aria.core.AriaManager;
/**
* Created by Aria.Lao on 2017/7/17.
* 下载任务池该池子为简单任务和任务组共用
*/
public class DownloadSharePool {
private static volatile DownloadSharePool INSTANCE;
public DownloadExecutePool executePool;
public BaseCachePool cachePool;
private DownloadSharePool() {
executePool = new DownloadExecutePool<>();
cachePool = new BaseCachePool<>();
}
public static DownloadSharePool getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new DownloadSharePool();
}
}
return INSTANCE;
}
}

@ -16,24 +16,24 @@
package com.arialyy.aria.core.queue.pool; package com.arialyy.aria.core.queue.pool;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.inf.AbsTask;
/** /**
* Created by lyy on 2016/8/14. * Created by lyy on 2016/8/14.
* 任务池 * 任务池
*/ */
public interface IPool<T extends ITask> { interface IPool<T extends AbsTask> {
/** /**
* 将下载任务添加到任务池中 * 将下载任务添加到任务池中
*/ */
public boolean putTask(T task); boolean putTask(T task);
/** /**
* 按照队列原则取出下载任务 * 按照队列原则取出下载任务
* *
* @return 返回null或者下载任务 * @return 返回null或者下载任务
*/ */
public T pollTask(); T pollTask();
/** /**
* 通过下载链接获取下载任务当任务不为空时队列将删除该下载任务 * 通过下载链接获取下载任务当任务不为空时队列将删除该下载任务
@ -41,7 +41,7 @@ public interface IPool<T extends ITask> {
* @param downloadUrl 下载链接 * @param downloadUrl 下载链接
* @return 返回null或者下载任务 * @return 返回null或者下载任务
*/ */
public T getTask(String downloadUrl); T getTask(String downloadUrl);
/** /**
* 删除任务池中的下载任务 * 删除任务池中的下载任务
@ -49,20 +49,20 @@ public interface IPool<T extends ITask> {
* @param task 下载任务 * @param task 下载任务
* @return true:移除成功 * @return true:移除成功
*/ */
public boolean removeTask(T task); boolean removeTask(T task);
/** /**
* 通过下载链接移除下载任务 * 通过key除下载任务
* *
* @param downloadUrl 下载链接 * @param key 下载链接
* @return true:移除成功 * @return true:移除成功
*/ */
public boolean removeTask(String downloadUrl); boolean removeTask(String key);
/** /**
* 池子大小 * 池子大小
* *
* @return 返回缓存池或者当前任务池大小 * @return 返回缓存池或者执行池大小
*/ */
public int size(); int size();
} }

@ -0,0 +1,28 @@
/*
* 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.queue.pool;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
/**
* Created by Aria.Lao on 2017/7/17.
*/
public class UploadExecutePool<TASK extends AbsTask> extends BaseExecutePool<TASK> {
@Override protected int getMaxSize() {
return AriaManager.getInstance(AriaManager.APP).getUploadConfig().getMaxTaskNum();
}
}

@ -0,0 +1,43 @@
/*
* 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.queue.pool;
import com.arialyy.aria.core.AriaManager;
/**
* Created by Aria.Lao on 2017/7/17.
* 下载任务池该池子为简单任务和任务组共用
*/
public class UploadSharePool {
private static volatile UploadSharePool INSTANCE;
public UploadExecutePool executePool;
public BaseCachePool cachePool;
private UploadSharePool() {
executePool = new UploadExecutePool();
cachePool = new BaseCachePool<>();
}
public static UploadSharePool getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new UploadSharePool();
}
}
return INSTANCE;
}
}

@ -21,9 +21,9 @@ import android.util.Log;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTask; import com.arialyy.aria.core.download.DownloadTask;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.inf.IEntity; import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.queue.ITaskQueue; import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.upload.UploadTask; import com.arialyy.aria.core.upload.UploadTask;
import java.util.Iterator; import java.util.Iterator;
@ -33,28 +33,32 @@ import java.util.concurrent.ConcurrentHashMap;
/** /**
* Created by lyy on 2017/6/4. * Created by lyy 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>> abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY extends AbsEntity, TASK extends AbsTask<ENTITY>, QUEUE extends ITaskQueue<TASK, TASK_ENTITY, ENTITY>>
implements ISchedulers<TASK> { implements ISchedulers<TASK> {
private static final String TAG = "AbsSchedulers"; private final String TAG = "AbsSchedulers";
/** static final int DOWNLOAD = 0xa1;
* 下载的动态生成的代理类后缀 static final int UPLOAD = 0xa2;
*/ static final int DOWNLOAD_GROUP = 0xa3;
String DOWNLOAD_PROXY_CLASS_SUFFIX = "$$DownloadListenerProxy";
/**
* 上传的动态生成的代理类后缀
*/
String UPLOAD_PROXY_CLASS_SUFFIX = "$$UploadListenerProxy";
protected QUEUE mQueue; protected QUEUE mQueue;
protected boolean isDownload = true;
private Map<String, ISchedulerListener<TASK>> mSchedulerListeners = new ConcurrentHashMap<>(); private Map<String, ISchedulerListener<TASK>> mSchedulerListeners = new ConcurrentHashMap<>();
private Map<String, AbsSchedulerListener<TASK>> mObservers = new ConcurrentHashMap<>(); private Map<String, AbsSchedulerListener<TASK>> mObservers = new ConcurrentHashMap<>();
/**
* 设置调度器类型
*/
abstract int getSchedulerType();
/**
* 设置代理类后缀名
*/
abstract String getProxySuffix();
/** /**
* @param targetName 观察者创建该监听器的对象类名 * @param targetName 观察者创建该监听器的对象类名
* @param schedulerListener {@link ISchedulerListener} * @param schedulerListener {@link ISchedulerListener}
@ -109,18 +113,14 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
private AbsSchedulerListener<TASK> createListener(String targetName) { private AbsSchedulerListener<TASK> createListener(String targetName) {
AbsSchedulerListener<TASK> listener = null; AbsSchedulerListener<TASK> listener = null;
try { try {
Class clazz = Class.forName( Class clazz = Class.forName(targetName + getProxySuffix());
targetName + (isDownload ? DOWNLOAD_PROXY_CLASS_SUFFIX : UPLOAD_PROXY_CLASS_SUFFIX));
listener = (AbsSchedulerListener<TASK>) clazz.newInstance(); listener = (AbsSchedulerListener<TASK>) clazz.newInstance();
} catch (ClassNotFoundException e) { } catch (ClassNotFoundException e) {
Log.e(TAG, targetName + ",没有Aria的Download或Upload注解方法"); Log.e(TAG, targetName + ",没有Aria的Download或Upload注解方法");
//e.printStackTrace();
} catch (InstantiationException e) { } catch (InstantiationException e) {
Log.e(TAG, e.getMessage()); Log.e(TAG, e.getMessage());
//e.printStackTrace();
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
Log.e(TAG, e.getMessage()); Log.e(TAG, e.getMessage());
//e.printStackTrace();
} }
return listener; return listener;
} }
@ -131,7 +131,6 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
Log.e(TAG, "请传入下载任务"); Log.e(TAG, "请传入下载任务");
return true; return true;
} }
callback(msg.what, task);
ENTITY entity = task.getEntity(); ENTITY entity = task.getEntity();
switch (msg.what) { switch (msg.what) {
case STOP: case STOP:
@ -140,7 +139,7 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
} }
case CANCEL: case CANCEL:
mQueue.removeTask(entity); mQueue.removeTask(entity);
if (mQueue.getExeTaskNum() < AriaManager.getInstance(AriaManager.APP) if (mQueue.getCurrentExePoolNum() < AriaManager.getInstance(AriaManager.APP)
.getUploadConfig() .getUploadConfig()
.getMaxTaskNum()) { .getMaxTaskNum()) {
startNextTask(); startNextTask();
@ -154,6 +153,7 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
handleFailTask(task); handleFailTask(task);
break; break;
} }
callback(msg.what, task);
return true; return true;
} }
@ -258,7 +258,7 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
/** /**
* 启动下一个任务条件任务停止取消下载任务完成 * 启动下一个任务条件任务停止取消下载任务完成
*/ */
private void startNextTask() { protected void startNextTask() {
TASK newTask = mQueue.getNextTask(); TASK newTask = mQueue.getNextTask();
if (newTask == null) { if (newTask == null) {
Log.w(TAG, "没有下一任务"); Log.w(TAG, "没有下一任务");
@ -268,4 +268,20 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
mQueue.startTask(newTask); mQueue.startTask(newTask);
} }
} }
/**
* 是否有下一任务
*
* @return {@code true} {@code false}
*/
boolean hasNextTask() {
return mQueue.getCurrentCachePoolNum() > 0;
}
/**
* 获取正在执行的队列数
*/
int getExeTaskNum() {
return mQueue.getCurrentExePoolNum();
}
} }

@ -0,0 +1,89 @@
/*
* 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 com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* Created by Aria.Lao on 2017/7/13.
* 下载任务和队列的映射表
*/
public class DQueueMapping {
public static final int QUEUE_TYPE_DOWNLOAD = 0xa1;
public static final int QUEUE_TYPE_DOWNLOAD_GROUP = 0xa2;
public static final int QUEUE_NONE = 0xab2;
private LinkedHashMap<String, Integer> types = new LinkedHashMap<>();
private static volatile DQueueMapping instance = null;
private DQueueMapping() {
}
public static DQueueMapping getInstance() {
if (instance == null) {
synchronized (AriaManager.LOCK) {
instance = new DQueueMapping();
}
}
return instance;
}
/**
* map中增加类型
*
* @param key 任务的key
* @param type {@link #QUEUE_TYPE_DOWNLOAD}{@link #QUEUE_TYPE_DOWNLOAD}
*/
public void addType(String key, int type) {
types.put(key, type);
}
/**
* @param key 任务的key
*/
public void removeType(String key) {
types.remove(key);
}
/**
* 获取下一个任务类型
*
* @return {@link #QUEUE_TYPE_DOWNLOAD}{@link #QUEUE_TYPE_DOWNLOAD}
*/
public int nextType() {
Iterator<Map.Entry<String, Integer>> iter = types.entrySet().iterator();
if (iter.hasNext()) {
Map.Entry<String, Integer> next = iter.next();
int type = next.getValue();
iter.remove();
return type;
}
return QUEUE_NONE;
}
public boolean canStart() {
return DownloadTaskQueue.getInstance().getCurrentExePoolNum()
+ DownloadGroupTaskQueue.getInstance().getCurrentExePoolNum() >= AriaManager.getInstance(
AriaManager.APP).getDownloadConfig().getMaxTaskNum();
}
}

@ -0,0 +1,74 @@
/*
* 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 com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTask;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.queue.DownloadGroupTaskQueue;
/**
* Created by AriaL on 2017/7/2.
* 任务组调度器
*/
public class DownloadGroupSchedulers extends
AbsSchedulers<DownloadGroupTaskEntity, DownloadGroupEntity, DownloadGroupTask, DownloadGroupTaskQueue> {
private final String TAG = "DownloadGroupSchedulers";
private static volatile DownloadGroupSchedulers INSTANCE = null;
private DownloadGroupSchedulers() {
mQueue = DownloadGroupTaskQueue.getInstance();
}
public static DownloadGroupSchedulers getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new DownloadGroupSchedulers();
}
}
return INSTANCE;
}
@Override int getSchedulerType() {
return DOWNLOAD_GROUP;
}
@Override String getProxySuffix() {
return "$$DownloadGroupListenerProxy";
}
@Override protected void startNextTask() {
if (getExeTaskNum() + DownloadSchedulers.getInstance().getExeTaskNum()
>= AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum()) {
return;
}
if (!DownloadSchedulers.getInstance().hasNextTask()) {
nextSelf();
} else {
Integer nextType = DQueueMapping.getInstance().nextType();
if (nextType == DQueueMapping.QUEUE_TYPE_DOWNLOAD) {
DownloadSchedulers.getInstance().nextSelf();
} else {
nextSelf();
}
}
}
void nextSelf() {
super.startNextTask();
}
}

@ -16,11 +16,13 @@
package com.arialyy.aria.core.scheduler; package com.arialyy.aria.core.scheduler;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTaskEntity; import com.arialyy.aria.core.download.DownloadTaskEntity;
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.nio.MappedByteBuffer;
/** /**
* Created by lyy on 2016/8/16. * Created by lyy on 2016/8/16.
@ -29,12 +31,11 @@ import com.arialyy.aria.core.download.DownloadTask;
public class DownloadSchedulers public class DownloadSchedulers
extends AbsSchedulers<DownloadTaskEntity, DownloadEntity, DownloadTask, DownloadTaskQueue> { extends AbsSchedulers<DownloadTaskEntity, DownloadEntity, DownloadTask, DownloadTaskQueue> {
private static final String TAG = "DownloadSchedulers"; private final String TAG = "DownloadSchedulers";
private static volatile DownloadSchedulers INSTANCE = null; private static volatile DownloadSchedulers INSTANCE = null;
private DownloadSchedulers() { private DownloadSchedulers() {
mQueue = DownloadTaskQueue.getInstance(); mQueue = DownloadTaskQueue.getInstance();
isDownload = true;
} }
public static DownloadSchedulers getInstance() { public static DownloadSchedulers getInstance() {
@ -45,4 +46,33 @@ public class DownloadSchedulers
} }
return INSTANCE; return INSTANCE;
} }
@Override int getSchedulerType() {
return DOWNLOAD;
}
@Override String getProxySuffix() {
return "$$DownloadListenerProxy";
}
@Override protected void startNextTask() {
if (getExeTaskNum() + DownloadGroupSchedulers.getInstance().getExeTaskNum()
>= AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum()) {
return;
}
if (!DownloadGroupSchedulers.getInstance().hasNextTask()) {
nextSelf();
} else {
Integer nextType = DQueueMapping.getInstance().nextType();
if (nextType == DQueueMapping.QUEUE_TYPE_DOWNLOAD_GROUP) {
DownloadGroupSchedulers.getInstance().nextSelf();
} else {
nextSelf();
}
}
}
void nextSelf() {
super.startNextTask();
}
} }

@ -17,54 +17,54 @@
package com.arialyy.aria.core.scheduler; package com.arialyy.aria.core.scheduler;
import android.os.Handler; import android.os.Handler;
import com.arialyy.aria.core.inf.ITask; import com.arialyy.aria.core.inf.AbsTask;
/** /**
* Created by lyy on 2016/11/2. * Created by lyy on 2016/11/2.
* 调度器功能接口 * 调度器功能接口
*/ */
public interface ISchedulers<Task extends ITask> extends Handler.Callback { public interface ISchedulers<Task extends AbsTask> extends Handler.Callback {
/** /**
* 断点支持 * 断点支持
*/ */
public static final int SUPPORT_BREAK_POINT = 9; int SUPPORT_BREAK_POINT = 9;
/** /**
* 任务预加载 * 任务预加载
*/ */
public static final int PRE = 0; int PRE = 0;
/** /**
* 任务预加载完成 * 任务预加载完成
*/ */
public static final int POST_PRE = 1; int POST_PRE = 1;
/** /**
* 任务开始 * 任务开始
*/ */
public static final int START = 2; int START = 2;
/** /**
* 任务停止 * 任务停止
*/ */
public static final int STOP = 3; int STOP = 3;
/** /**
* 任务失败 * 任务失败
*/ */
public static final int FAIL = 4; int FAIL = 4;
/** /**
* 任务取消 * 任务取消
*/ */
public static final int CANCEL = 5; int CANCEL = 5;
/** /**
* 任务完成 * 任务完成
*/ */
public static final int COMPLETE = 6; int COMPLETE = 6;
/** /**
* 任务处理中 * 任务处理中
*/ */
public static final int RUNNING = 7; int RUNNING = 7;
/** /**
* 恢复任务 * 恢复任务
*/ */
public static final int RESUME = 8; int RESUME = 8;
/** /**
* 注册下载器监听一个观察者只能注册一次监听 * 注册下载器监听一个观察者只能注册一次监听
@ -72,26 +72,25 @@ public interface ISchedulers<Task extends ITask> extends Handler.Callback {
* @param targetName 观察者创建该监听器的对象类名 * @param targetName 观察者创建该监听器的对象类名
* @param schedulerListener {@link ISchedulerListener} * @param schedulerListener {@link ISchedulerListener}
*/ */
public void addSchedulerListener(String targetName, ISchedulerListener<Task> schedulerListener); void addSchedulerListener(String targetName, ISchedulerListener<Task> schedulerListener);
/** /**
* @param targetName 观察者创建该监听器的对象类名 * @param targetName 观察者创建该监听器的对象类名
* 取消注册监听器 * 取消注册监听器
*/ */
public void removeSchedulerListener(String targetName, void removeSchedulerListener(String targetName, ISchedulerListener<Task> schedulerListener);
ISchedulerListener<Task> schedulerListener);
/** /**
* 将当前类注册到Aria * 将当前类注册到Aria
* *
* @param obj 观察者类 * @param obj 观察者类
*/ */
public void register(Object obj); void register(Object obj);
/** /**
* 移除注册 * 移除注册
* *
* @param obj 观察者类 * @param obj 观察者类
*/ */
public void unRegister(Object obj); void unRegister(Object obj);
} }

@ -32,7 +32,6 @@ public class UploadSchedulers
private UploadSchedulers() { private UploadSchedulers() {
mQueue = UploadTaskQueue.getInstance(); mQueue = UploadTaskQueue.getInstance();
isDownload = false;
} }
public static UploadSchedulers getInstance() { public static UploadSchedulers getInstance() {
@ -44,4 +43,12 @@ public class UploadSchedulers
return INSTANCE; return INSTANCE;
} }
@Override int getSchedulerType() {
return UPLOAD;
}
@Override String getProxySuffix() {
return "$$UploadListenerProxy";
}
} }

@ -15,60 +15,12 @@
*/ */
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import com.arialyy.aria.core.inf.IEventListener;
/** /**
* Created by lyy on 2017/2/9. * Created by lyy on 2017/2/9.
* 上传监听 * 上传监听
*/ */
public interface IUploadListener { interface IUploadListener extends IEventListener {
/**
* 预处理
*/
public void onPre();
/**
* 预处理完成
*/
public void onPostPre(long fileSize);
/**
* 开始上传
*/
public void onStart();
/**
* 恢复上传
*
* @param resumeLocation 上次上传停止位置
*/
public void onResume(long resumeLocation);
/**
* 停止上传
*
* @param stopLocation 上传停止位置
*/
public void onStop(long stopLocation);
/**
* 上传进度
*
* @param currentLocation 当前进度
*/
public void onProgress(long currentLocation);
/**
* 取消上传
*/
public void onCancel();
/**
* 上传成功
*/
public void onComplete();
/**
* 上传失败
*/
public void onFail();
} }

@ -0,0 +1,78 @@
/*
* 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.upload;
import com.arialyy.aria.core.AriaManager;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;
import static java.util.Collections.unmodifiableSet;
/**
* Created by Aria.Lao on 2017/7/10.
* 代理参数获取
*/
public class ProxyHelper {
public Set<String> downloadCounter, uploadCounter, downloadGroupCounter;
public static volatile ProxyHelper INSTANCE = null;
private ProxyHelper() {
init();
}
public static ProxyHelper getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new ProxyHelper();
}
}
return INSTANCE;
}
private void init() {
try {
Class clazz = Class.forName("com.arialyy.aria.ProxyClassCounter");
Method download = clazz.getMethod("getDownloadCounter");
Method downloadGroup = clazz.getMethod("getDownloadGroupCounter");
Method upload = clazz.getMethod("getUploadCounter");
Object object = clazz.newInstance();
Object dc = download.invoke(object);
if (dc != null) {
downloadCounter = unmodifiableSet((Set<String>) dc);
}
Object dgc = downloadGroup.invoke(object);
if (dgc != null) {
downloadGroupCounter = unmodifiableSet((Set<String>) dgc);
}
Object uc = upload.invoke(object);
if (uc != null) {
uploadCounter = unmodifiableSet((Set<String>) uc);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}

@ -17,25 +17,18 @@ package com.arialyy.aria.core.upload;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import com.arialyy.aria.core.inf.AbsEntity; import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.orm.Ignore; import com.arialyy.aria.orm.Ignore;
import com.arialyy.aria.orm.Primary;
/** /**
* Created by lyy on 2017/2/9. * Created by lyy on 2017/2/9.
* 上传文件实体 * 上传文件实体
*/ */
public class UploadEntity extends AbsEntity implements Parcelable { public class UploadEntity extends AbsNormalEntity implements Parcelable {
@Primary
private String filePath; //文件路径 private String filePath; //文件路径
private boolean isComplete = false;
public boolean isComplete() {
return isComplete;
}
public void setComplete(boolean complete) {
isComplete = complete;
}
public String getFilePath() { public String getFilePath() {
return filePath; return filePath;
@ -45,6 +38,10 @@ public class UploadEntity extends AbsEntity implements Parcelable {
this.filePath = filePath; this.filePath = filePath;
} }
@Override public String getKey() {
return filePath;
}
public UploadEntity() { public UploadEntity() {
} }
@ -55,13 +52,11 @@ public class UploadEntity extends AbsEntity implements Parcelable {
@Override public void writeToParcel(Parcel dest, int flags) { @Override public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags); super.writeToParcel(dest, flags);
dest.writeString(this.filePath); dest.writeString(this.filePath);
dest.writeByte(this.isComplete ? (byte) 1 : (byte) 0);
} }
protected UploadEntity(Parcel in) { protected UploadEntity(Parcel in) {
super(in); super(in);
this.filePath = in.readString(); this.filePath = in.readString();
this.isComplete = in.readByte() != 0;
} }
@Ignore public static final Creator<UploadEntity> CREATOR = new Creator<UploadEntity>() { @Ignore public static final Creator<UploadEntity> CREATOR = new Creator<UploadEntity>() {

@ -18,8 +18,7 @@ package com.arialyy.aria.core.upload;
/** /**
* Created by lyy on 2017/2/23. * Created by lyy on 2017/2/23.
*/ */
class UploadListener implements IUploadListener {
public class UploadListener implements IUploadListener {
@Override public void onPre() { @Override public void onPre() {
} }
@ -28,7 +27,7 @@ public class UploadListener implements IUploadListener {
} }
@Override public void onStart() { @Override public void onStart(long startLocation) {
} }

@ -17,30 +17,24 @@ package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.AbsCmd; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.command.CmdFactory; import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.download.DownloadReceiver; import com.arialyy.aria.core.inf.AbsReceiver;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.IReceiver; import com.arialyy.aria.core.inf.IReceiver;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulerListener; import com.arialyy.aria.core.scheduler.ISchedulerListener;
import com.arialyy.aria.core.scheduler.UploadSchedulers; import com.arialyy.aria.core.scheduler.UploadSchedulers;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.regex.Pattern;
/** /**
* Created by lyy on 2017/2/6. * Created by lyy on 2017/2/6.
* 上传功能接收器 * 上传功能接收器
*/ */
public class UploadReceiver implements IReceiver<UploadEntity> { public class UploadReceiver extends AbsReceiver<UploadEntity> {
private static final String TAG = "DownloadReceiver"; private static final String TAG = "DownloadReceiver";
public String targetName;
public Object obj;
public ISchedulerListener<UploadTask> listener; public ISchedulerListener<UploadTask> listener;
/** /**
@ -50,17 +44,7 @@ public class UploadReceiver implements IReceiver<UploadEntity> {
*/ */
public UploadTarget load(@NonNull String filePath) { public UploadTarget load(@NonNull String filePath) {
CheckUtil.checkUploadPath(filePath); CheckUtil.checkUploadPath(filePath);
UploadEntity entity = UploadEntity.findData(UploadEntity.class, "filePath=?", filePath); return new UploadTarget(filePath, targetName);
if (entity == null) {
entity = new UploadEntity();
}
String regex = "[/|\\\\|//]";
Pattern p = Pattern.compile(regex);
String[] strs = p.split(filePath);
String fileName = strs[strs.length - 1];
entity.setFileName(fileName);
entity.setFilePath(filePath);
return new UploadTarget(entity, targetName);
} }
/** /**
@ -68,41 +52,39 @@ public class UploadReceiver implements IReceiver<UploadEntity> {
*/ */
public UploadEntity getUploadEntity(String filePath) { public UploadEntity getUploadEntity(String filePath) {
CheckUtil.checkUploadPath(filePath); CheckUtil.checkUploadPath(filePath);
return DbEntity.findData(UploadEntity.class, "filePath=?", filePath); return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath);
} }
/** /**
* 下载任务是否存在 * 下载任务是否存在
*/ */
@Override public boolean taskExists(String filePath) { @Override public boolean taskExists(String filePath) {
return DbEntity.findData(UploadEntity.class, "filePath=?", filePath) != null; return DbEntity.findFirst(UploadEntity.class, "filePath=?", filePath) != null;
} }
@Override public List<UploadEntity> getTaskList() { @Override public List<UploadEntity> getSimpleTaskList() {
return DbEntity.findAllData(UploadEntity.class); return DbEntity.findAllData(UploadEntity.class);
} }
@Override public void stopAllTask() { @Override public void stopAllTask() {
List<UploadEntity> allEntity = DbEntity.findAllData(UploadEntity.class); AriaManager.getInstance(AriaManager.APP)
List<AbsCmd> stopCmds = new ArrayList<>(); .setCmd(NormalCmdFactory.getInstance()
for (UploadEntity entity : allEntity) { .createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL))
if (entity.getState() == IEntity.STATE_RUNNING) { .exe();
stopCmds.add(
CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), CmdFactory.TASK_STOP));
}
}
AriaManager.getInstance(AriaManager.APP).setCmds(stopCmds).exe();
} }
@Override public void removeAllTask() { /**
* 删除所有任务
*
* @param removeFile {@code true} 删除已经上传完成的任务不仅删除上传记录还会删除已经上传完成的文件{@code false}
* 如果文件已经上传完成只删除上传记录
*/
@Override public void removeAllTask(boolean removeFile) {
final AriaManager am = AriaManager.getInstance(AriaManager.APP); final AriaManager am = AriaManager.getInstance(AriaManager.APP);
List<UploadEntity> allEntity = DbEntity.findAllData(UploadEntity.class);
List<AbsCmd> cancelCmds = new ArrayList<>(); am.setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(),
for (UploadEntity entity : allEntity) { NormalCmdFactory.TASK_CANCEL_ALL)).exe();
cancelCmds.add(
CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), CmdFactory.TASK_CANCEL));
}
am.setCmds(cancelCmds).exe();
Set<String> keys = am.getReceiver().keySet(); Set<String> keys = am.getReceiver().keySet();
for (String key : keys) { for (String key : keys) {
IReceiver receiver = am.getReceiver().get(key); IReceiver receiver = am.getReceiver().get(key);
@ -118,14 +100,19 @@ public class UploadReceiver implements IReceiver<UploadEntity> {
/** /**
* 添加调度器回调 * 添加调度器回调
*
* @see #register()
*/ */
public UploadReceiver addSchedulerListener(ISchedulerListener<UploadTask> listener) { @Deprecated public UploadReceiver addSchedulerListener(ISchedulerListener<UploadTask> listener) {
this.listener = listener; this.listener = listener;
UploadSchedulers.getInstance().addSchedulerListener(targetName, listener); UploadSchedulers.getInstance().addSchedulerListener(targetName, listener);
return this; return this;
} }
@Override public void removeSchedulerListener() { /**
* @see #unRegister()
*/
@Deprecated @Override public void removeSchedulerListener() {
if (listener != null) { if (listener != null) {
UploadSchedulers.getInstance().removeSchedulerListener(targetName, listener); UploadSchedulers.getInstance().removeSchedulerListener(targetName, listener);
} }
@ -135,11 +122,19 @@ public class UploadReceiver implements IReceiver<UploadEntity> {
* 将当前类注册到Aria * 将当前类注册到Aria
*/ */
public UploadReceiver register() { public UploadReceiver register() {
String className = obj.getClass().getName();
Set<String> cCounter = ProxyHelper.getInstance().uploadCounter;
if (cCounter != null && cCounter.contains(className)) {
UploadSchedulers.getInstance().register(obj); UploadSchedulers.getInstance().register(obj);
}
return this; return this;
} }
@Override public void unRegister() { @Override public void unRegister() {
String className = obj.getClass().getName();
Set<String> dCounter = ProxyHelper.getInstance().uploadCounter;
if (dCounter != null && dCounter.contains(className)) {
UploadSchedulers.getInstance().unRegister(obj); UploadSchedulers.getInstance().unRegister(obj);
} }
}
} }

@ -16,28 +16,49 @@
package com.arialyy.aria.core.upload; package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.core.RequestEnum; import com.arialyy.aria.core.inf.AbsNormalTarget;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.queue.UploadTaskQueue; import com.arialyy.aria.core.queue.UploadTaskQueue;
import com.arialyy.aria.orm.DbEntity; import com.arialyy.aria.orm.DbEntity;
import java.util.Map; import java.util.regex.Pattern;
/** /**
* Created by lyy on 2017/2/28. * Created by lyy on 2017/2/28.
*/ */
public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> { public class UploadTarget extends AbsNormalTarget<UploadTarget, UploadEntity, UploadTaskEntity> {
UploadTarget(UploadEntity entity, String targetName) { UploadTarget(String filePath, String targetName) {
this.entity = entity; this.mTargetName = targetName;
this.targetName = targetName; mTaskEntity = DbEntity.findFirst(UploadTaskEntity.class, "key=?", filePath);
taskEntity = new UploadTaskEntity(entity); if (mTaskEntity == null) {
mTaskEntity = new UploadTaskEntity();
mTaskEntity.entity = getUploadEntity(filePath);
}
if (mTaskEntity.entity == null) {
mTaskEntity.entity = getUploadEntity(filePath);
}
mEntity = mTaskEntity.entity;
}
private UploadEntity getUploadEntity(String filePath) {
UploadEntity entity = UploadEntity.findFirst(UploadEntity.class, "filePath=?", filePath);
if (entity == null) {
entity = new UploadEntity();
String regex = "[/|\\\\|//]";
Pattern p = Pattern.compile(regex);
String[] strs = p.split(filePath);
String fileName = strs[strs.length - 1];
entity.setFileName(fileName);
entity.setFilePath(filePath);
entity.insert();
}
return entity;
} }
/** /**
* 设置userAgent * 设置userAgent
*/ */
public UploadTarget setUserAngent(@NonNull String userAgent) { public UploadTarget setUserAngent(@NonNull String userAgent) {
taskEntity.userAgent = userAgent; mTaskEntity.userAgent = userAgent;
return this; return this;
} }
@ -47,7 +68,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* @param uploadUrl 上传路径 * @param uploadUrl 上传路径
*/ */
public UploadTarget setUploadUrl(@NonNull String uploadUrl) { public UploadTarget setUploadUrl(@NonNull String uploadUrl) {
taskEntity.uploadUrl = uploadUrl; mTaskEntity.uploadUrl = uploadUrl;
return this; return this;
} }
@ -57,7 +78,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* @param attachment 附件key * @param attachment 附件key
*/ */
public UploadTarget setAttachment(@NonNull String attachment) { public UploadTarget setAttachment(@NonNull String attachment) {
taskEntity.attachment = attachment; mTaskEntity.attachment = attachment;
return this; return this;
} }
@ -65,7 +86,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* 设置文件名 * 设置文件名
*/ */
public UploadTarget setFileName(String fileName) { public UploadTarget setFileName(String fileName) {
entity.setFileName(fileName); mEntity.setFileName(fileName);
return this; return this;
} }
@ -75,28 +96,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* @param contentType tipmultipart/form-data * @param contentType tipmultipart/form-data
*/ */
public UploadTarget setContentType(String contentType) { public UploadTarget setContentType(String contentType) {
taskEntity.contentType = contentType; mTaskEntity.contentType = contentType;
return this;
}
/**
* 给url请求添加头部
*
* @param key 头部key
* @param header 头部value
*/
public UploadTarget addHeader(@NonNull String key, @NonNull String header) {
super._addHeader(key, header);
return this;
}
/**
* 给url请求添加头部
*
* @param headers key为http头部的keyValue为http头对应的配置
*/
public UploadTarget addHeaders(Map<String, String> headers) {
super._addHeaders(headers);
return this; return this;
} }
@ -104,28 +104,14 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* 下载任务是否存在 * 下载任务是否存在
*/ */
@Override public boolean taskExists() { @Override public boolean taskExists() {
return UploadTaskQueue.getInstance().getTask(entity.getFilePath()) != null; return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
}
/**
* 设置请求类型
*
* @param requestEnum {@link RequestEnum}
*/
public UploadTarget setRequestMode(RequestEnum requestEnum) {
super._setRequestMode(requestEnum);
return this;
}
private UploadEntity getDownloadEntity() {
return entity;
} }
/** /**
* 是否在下载 * 是否在下载
*/ */
public boolean isUploading() { public boolean isUploading() {
UploadTask task = UploadTaskQueue.getInstance().getTask(entity); UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity);
return task != null && task.isRunning(); return task != null && task.isRunning();
} }
} }

@ -51,7 +51,7 @@ final class UploadUtil implements Runnable {
UploadUtil(UploadTaskEntity taskEntity, IUploadListener listener) { UploadUtil(UploadTaskEntity taskEntity, IUploadListener listener) {
mTaskEntity = taskEntity; mTaskEntity = taskEntity;
CheckUtil.checkTaskEntity(taskEntity); CheckUtil.checkTaskEntity(taskEntity);
mUploadEntity = taskEntity.uploadEntity; mUploadEntity = taskEntity.getEntity();
if (listener == null) { if (listener == null) {
throw new IllegalArgumentException("上传监听不能为空"); throw new IllegalArgumentException("上传监听不能为空");
} }
@ -109,7 +109,7 @@ final class UploadUtil implements Runnable {
for (String key : keys) { for (String key : keys) {
addFormField(writer, key, mTaskEntity.formFields.get(key)); addFormField(writer, key, mTaskEntity.formFields.get(key));
} }
mListener.onStart(); mListener.onStart(0);
uploadFile(writer, mTaskEntity.attachment, uploadFile); uploadFile(writer, mTaskEntity.attachment, uploadFile);
Log.d(TAG, finish(writer) + ""); Log.d(TAG, finish(writer) + "");
} catch (IOException e) { } catch (IOException e) {
@ -162,11 +162,11 @@ final class UploadUtil implements Runnable {
writer.append("Content-Disposition: form-data; name=\"") writer.append("Content-Disposition: form-data; name=\"")
.append(attachment) .append(attachment)
.append("\"; filename=\"") .append("\"; filename=\"")
.append(mTaskEntity.uploadEntity.getFileName()) .append(mTaskEntity.getEntity().getFileName())
.append("\"") .append("\"")
.append(LINE_END); .append(LINE_END);
writer.append("Content-Type: ") writer.append("Content-Type: ")
.append(URLConnection.guessContentTypeFromName(mTaskEntity.uploadEntity.getFileName())) .append(URLConnection.guessContentTypeFromName(mTaskEntity.getEntity().getFileName()))
.append(LINE_END); .append(LINE_END);
writer.append("Content-Transfer-Encoding: binary").append(LINE_END); writer.append("Content-Transfer-Encoding: binary").append(LINE_END);
writer.append(LINE_END); writer.append(LINE_END);

@ -17,7 +17,11 @@ package com.arialyy.aria.orm;
import android.text.TextUtils; import android.text.TextUtils;
import com.arialyy.aria.core.download.DownloadEntity; import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadGroupEntity;
import com.arialyy.aria.core.download.DownloadGroupTaskEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -28,7 +32,7 @@ import java.util.Map;
public class DBConfig { public class DBConfig {
static Map<String, Class> mapping = new HashMap<>(); static Map<String, Class> mapping = new HashMap<>();
static String DB_NAME; static String DB_NAME;
static int VERSION = 3; static int VERSION = 10;
static { static {
if (TextUtils.isEmpty(DB_NAME)) { if (TextUtils.isEmpty(DB_NAME)) {
@ -41,6 +45,10 @@ public class DBConfig {
static { static {
mapping.put("DownloadEntity", DownloadEntity.class); mapping.put("DownloadEntity", DownloadEntity.class);
mapping.put("DownloadGroupEntity", DownloadGroupEntity.class);
mapping.put("DownloadTaskEntity", DownloadTaskEntity.class);
mapping.put("DownloadGroupTaskEntity", DownloadGroupTaskEntity.class);
mapping.put("UploadEntity", UploadEntity.class); mapping.put("UploadEntity", UploadEntity.class);
mapping.put("UploadTaskEntity", UploadTaskEntity.class);
} }
} }

@ -19,8 +19,10 @@ package com.arialyy.aria.orm;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
/** /**
* Created by lyy on 2015/11/2. * Created by lyy on 2015/11/2.
@ -34,6 +36,13 @@ public class DbEntity {
} }
/**
* 直接执行sql语句
*/
public static void exeSql(String sql) {
DbUtil.getInstance().exeSql(sql);
}
/** /**
* 查询所有数据 * 查询所有数据
* *
@ -55,7 +64,7 @@ public class DbEntity {
/** /**
* 查询一组数据 * 查询一组数据
* <code> * <code>
* DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", downloadUrl); * DownloadEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl);
* </code> * </code>
* *
* @return 没有数据返回null * @return 没有数据返回null
@ -68,12 +77,12 @@ public class DbEntity {
/** /**
* 查询一行数据 * 查询一行数据
* <code> * <code>
* DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", downloadUrl); * DownloadEntity.findFirst(DownloadEntity.class, "downloadUrl=?", downloadUrl);
* </code> * </code>
* *
* @return 没有数据返回null * @return 没有数据返回null
*/ */
public static <T extends DbEntity> T findData(Class<T> clazz, String... expression) { public static <T extends DbEntity> T findFirst(Class<T> clazz, String... expression) {
DbUtil util = DbUtil.getInstance(); DbUtil util = DbUtil.getInstance();
List<T> datas = util.findData(clazz, expression); List<T> datas = util.findData(clazz, expression);
return datas == null ? null : datas.size() > 0 ? datas.get(0) : null; return datas == null ? null : datas.size() > 0 ? datas.get(0) : null;
@ -97,7 +106,6 @@ public class DbEntity {
* 删除当前数据 * 删除当前数据
*/ */
public void deleteData() { public void deleteData() {
//mUtil.delData(getClass(), new Object[] { "rowid" }, new Object[] { rowID });
deleteData(getClass(), "rowid=?", rowID + ""); deleteData(getClass(), "rowid=?", rowID + "");
} }
@ -124,7 +132,7 @@ public class DbEntity {
*/ */
public void save() { public void save() {
synchronized (LOCK) { synchronized (LOCK) {
if (DbUtil.getInstance().tableExists(getClass()) && thisIsExist()) { if (thisIsExist()) {
update(); update();
} else { } else {
insert(); insert();
@ -136,7 +144,8 @@ public class DbEntity {
* 查找数据在表中是否存在 * 查找数据在表中是否存在
*/ */
private boolean thisIsExist() { private boolean thisIsExist() {
return findData(getClass(), "rowid=?", rowID + "") != null; DbUtil util = DbUtil.getInstance();
return util.isExist(getClass(), rowID);
} }
/** /**
@ -147,7 +156,7 @@ public class DbEntity {
updateRowID(); updateRowID();
} }
private <T extends DbEntity> T findData(Class<T> clazz, @NonNull String[] wheres, private <T extends DbEntity> T findFirst(Class<T> clazz, @NonNull String[] wheres,
@NonNull String[] values) { @NonNull String[] values) {
DbUtil util = DbUtil.getInstance(); DbUtil util = DbUtil.getInstance();
List<T> list = util.findData(clazz, wheres, values); List<T> list = util.findData(clazz, wheres, values);
@ -156,7 +165,7 @@ public class DbEntity {
private void updateRowID() { private void updateRowID() {
try { try {
Field[] fields = CommonUtil.getFields(getClass()); List<Field> fields = CommonUtil.getAllFields(getClass());
List<String> where = new ArrayList<>(); List<String> where = new ArrayList<>();
List<String> values = new ArrayList<>(); List<String> values = new ArrayList<>();
for (Field field : fields) { for (Field field : fields) {
@ -165,9 +174,22 @@ public class DbEntity {
continue; continue;
} }
where.add(field.getName()); where.add(field.getName());
Type type = field.getType();
if (SqlHelper.isOneToOne(field)) {
values.add(SqlHelper.getOneToOneParams(field));
} else if (type == List.class) {
if (SqlHelper.isOneToMany(field)) {
values.add(SqlHelper.getOneToManyElementParams(field));
} else {
values.add(SqlHelper.list2Str(this, field));
}
} else if (type == Map.class) {
values.add(SqlHelper.map2Str((Map<String, String>) field.get(this)));
} else {
values.add(field.get(this) + ""); values.add(field.get(this) + "");
} }
DbEntity entity = findData(getClass(), where.toArray(new String[where.size()]), }
DbEntity entity = findFirst(getClass(), where.toArray(new String[where.size()]),
values.toArray(new String[values.size()])); values.toArray(new String[values.size()]));
if (entity != null) { if (entity != null) {
rowID = entity.rowID; rowID = entity.rowID;

@ -64,6 +64,13 @@ public class DbUtil {
return INSTANCE; return INSTANCE;
} }
/**
* 执行sql语句
*/
void exeSql(String sql) {
mDb.execSQL(sql);
}
/** /**
* 删除某条数据 * 删除某条数据
*/ */
@ -97,6 +104,18 @@ public class DbUtil {
return SqlHelper.findData(mDb, clazz, expression); return SqlHelper.findData(mDb, clazz, expression);
} }
/**
* 通过rowId判断数据是否存在
*/
synchronized <T extends DbEntity> boolean isExist(Class<T> clazz, int rowId) {
checkDb();
String sql = "SELECT rowid FROM " + CommonUtil.getClassName(clazz) + " WHERE rowid=" + rowId;
Cursor cursor = mDb.rawQuery(sql, null);
boolean isExist = cursor.getCount() > 0;
cursor.close();
return isExist;
}
/** /**
* 条件查寻数据 * 条件查寻数据
*/ */
@ -127,7 +146,7 @@ public class DbUtil {
SqlHelper.createTable(mDb, clazz, tableName); SqlHelper.createTable(mDb, clazz, tableName);
} }
private void checkDb(){ private void checkDb() {
if (mDb == null || !mDb.isOpen()) { if (mDb == null || !mDb.isOpen()) {
mDb = mHelper.getReadableDatabase(); mDb = mHelper.getReadableDatabase();
} }
@ -175,7 +194,7 @@ public class DbUtil {
Log.e(TAG, "请输入删除条件"); Log.e(TAG, "请输入删除条件");
return -1; return -1;
} else if (wheres.length != values.length) { } else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等"); Log.e(TAG, "groupName 和 vaule 长度不相等");
return -1; return -1;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();

@ -0,0 +1,32 @@
/*
* 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.orm;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by AriaL on 2017/7/4.
* 基本类型的List只能用于常见的数据类型如果是一对多的复杂数据结构需要使用{@link OneToMany}
*/
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface NormalList {
/**
* 数据类型
*/
Class clazz();
}

@ -0,0 +1,36 @@
/*
* 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.orm;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by AriaL on 2017/7/4.
* 一对多
*/
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToMany {
/**
* 关联的表
*/
Class<? extends DbEntity> table();
/**
* 关联的主键
*/
String key();
}

@ -0,0 +1,38 @@
/*
* 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.orm;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by AriaL on 2017/7/4.
* 一对一
*/
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface OneToOne {
/**
* 关联的表
*/
Class<? extends DbEntity> table();
/**
* 关联的主键
*/
String key();
}

@ -25,6 +25,6 @@ import java.lang.annotation.Target;
* Created by lyy on 2015/11/2. * Created by lyy on 2015/11/2.
* 表ID字段指定 * 表ID字段指定
*/ */
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id { @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Primary {
int value() default -1; int value() default -1;
} }

@ -28,9 +28,13 @@ import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Set; import java.util.Set;
/** /**
@ -186,11 +190,26 @@ final class SqlHelper extends SQLiteOpenHelper {
sql = String.format(sql, params); sql = String.format(sql, params);
print(FIND_DATA, sql); print(FIND_DATA, sql);
Cursor cursor = db.rawQuery(sql, null); Cursor cursor = db.rawQuery(sql, null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
cursor.close();
close(db); close(db);
return data; return data;
} }
/**
* 条件查寻数据
*/
static synchronized <T extends DbEntity> List<T> findData(SQLiteDatabase db, String tableName,
String... expression) {
Class<T> clazz = null;
try {
clazz = (Class<T>) Class.forName(tableName);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return findData(db, clazz, expression);
}
/** /**
* 条件查寻数据 * 条件查寻数据
*/ */
@ -201,7 +220,7 @@ final class SqlHelper extends SQLiteOpenHelper {
Log.e(TAG, "请输入查询条件"); Log.e(TAG, "请输入查询条件");
return null; return null;
} else if (wheres.length != values.length) { } else if (wheres.length != values.length) {
Log.e(TAG, "key 和 vaule 长度不相等"); Log.e(TAG, "groupName 和 vaule 长度不相等");
return null; return null;
} }
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
@ -214,7 +233,8 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
print(FIND_DATA, sb.toString()); print(FIND_DATA, sb.toString());
Cursor cursor = db.rawQuery(sb.toString(), null); Cursor cursor = db.rawQuery(sb.toString(), null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
cursor.close();
close(db); close(db);
return data; return data;
} }
@ -228,7 +248,8 @@ final class SqlHelper extends SQLiteOpenHelper {
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz)); sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz));
print(FIND_ALL_DATA, sb.toString()); print(FIND_ALL_DATA, sb.toString());
Cursor cursor = db.rawQuery(sb.toString(), null); Cursor cursor = db.rawQuery(sb.toString(), null);
List<T> data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; List<T> data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null;
cursor.close();
close(db); close(db);
return data; return data;
} }
@ -270,11 +291,26 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
sb.append(i > 0 ? ", " : ""); sb.append(i > 0 ? ", " : "");
try { try {
Object value = field.get(dbEntity); String value;
sb.append(field.getName()) sb.append(field.getName()).append("='");
.append("='") Type type = field.getType();
.append(value == null ? "" : value.toString()) if (type == Map.class) {
.append("'"); value = map2Str((Map<String, String>) field.get(dbEntity));
} else if (type == List.class) {
if (isOneToMany(field)) {
value = getOneToManyElementParams(field);
} else {
value = list2Str(dbEntity, field);
}
} else if (isOneToOne(field)) {
value = getOneToOneParams(field);
} else {
Object obj = field.get(dbEntity);
value = obj == null ? "" : obj.toString();
}
sb.append(value == null ? "" : value);
sb.append("'");
} catch (IllegalAccessException e) { } catch (IllegalAccessException e) {
e.printStackTrace(); e.printStackTrace();
} }
@ -304,11 +340,13 @@ final class SqlHelper extends SQLiteOpenHelper {
continue; continue;
} }
sb.append(i > 0 ? ", " : ""); sb.append(i > 0 ? ", " : "");
//sb.append(getFieldName(field.getType(), field));
sb.append(field.getName()); sb.append(field.getName());
i++; i++;
} }
sb.append(") VALUES ("); sb.append(") VALUES (");
i = 0; i = 0;
try {
for (Field field : fields) { for (Field field : fields) {
field.setAccessible(true); field.setAccessible(true);
if (ignoreField(field)) { if (ignoreField(field)) {
@ -316,13 +354,26 @@ final class SqlHelper extends SQLiteOpenHelper {
} }
sb.append(i > 0 ? ", " : ""); sb.append(i > 0 ? ", " : "");
sb.append("'"); sb.append("'");
try { Type type = field.getType();
sb.append(field.get(dbEntity)).append("'"); if (type == Map.class) {
} catch (IllegalAccessException e) { sb.append(map2Str((Map<String, String>) field.get(dbEntity)));
e.printStackTrace(); } else if (type == List.class) {
if (isOneToMany(field)) {
sb.append(getOneToManyElementParams(field));
} else {
sb.append(list2Str(dbEntity, field));
}
} else if (isOneToOne(field)) {
sb.append(getOneToOneParams(field));
} else {
sb.append(field.get(dbEntity));
} }
sb.append("'");
i++; i++;
} }
} catch (IllegalAccessException e) {
e.printStackTrace();
}
sb.append(")"); sb.append(")");
print(INSERT_DATA, sb.toString()); print(INSERT_DATA, sb.toString());
db.execSQL(sb.toString()); db.execSQL(sb.toString());
@ -330,6 +381,104 @@ final class SqlHelper extends SQLiteOpenHelper {
close(db); close(db);
} }
/**
* 获取一对一参数
*/
static String getOneToOneParams(Field field) {
OneToOne oneToOne = field.getAnnotation(OneToOne.class);
if (oneToOne == null) {
throw new IllegalArgumentException("@OneToOne注解的对象必须要有@Primary注解的字段");
}
return oneToOne.table().getName() + "$$" + oneToOne.key();
}
/**
* 获取List一对多参数
*
* @param field list反射字段
*/
static String getOneToManyElementParams(Field field) {
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
if (oneToMany == null) {
throw new IllegalArgumentException("一对多元素必须被@OneToMany注解");
}
//关联的表名
String tableName = oneToMany.table().getName();
//关联的字段
String key = oneToMany.key();
return tableName + "$$" + key;
}
/**
* 列表数据转字符串
*
* @param field list反射字段
*/
static String list2Str(DbEntity dbEntity, Field field) throws IllegalAccessException {
NormalList normalList = field.getAnnotation(NormalList.class);
if (normalList == null) {
throw new IllegalArgumentException("List中元素必须被@NormalList注解");
}
List list = (List) field.get(dbEntity);
if (list == null || list.isEmpty()) return "";
StringBuilder sb = new StringBuilder();
for (Object aList : list) {
sb.append(aList).append("$$");
}
return sb.toString();
}
/**
* 字符串转列表
*
* @param str 数据库中的字段
* @return 如果str为null则返回null
*/
private static List str2List(String str, Field field) {
NormalList normalList = field.getAnnotation(NormalList.class);
if (normalList == null) {
throw new IllegalArgumentException("List中元素必须被@NormalList注解");
}
if (TextUtils.isEmpty(str)) return null;
String[] datas = str.split("$$");
List list = new ArrayList();
String type = normalList.clazz().getName();
for (String data : datas) {
list.add(checkData(data, type));
}
return list;
}
private static Object checkData(String type, String data) {
switch (type) {
case "String":
return data;
case "int":
case "Integer":
return Integer.parseInt(data);
case "double":
case "Double":
return Double.parseDouble(data);
case "float":
case "Float":
return Float.parseFloat(data);
}
return null;
}
/**
* 查找class的主键字段
*
* @return 返回主键字段名
*/
private static String getPrimaryName(Class<? extends DbEntity> clazz) {
List<Field> fields = CommonUtil.getAllFields(clazz);
for (Field field : fields) {
if (isPrimary(field)) return field.getName();
}
return null;
}
/** /**
* 查找表是否存在 * 查找表是否存在
* *
@ -380,9 +529,13 @@ final class SqlHelper extends SQLiteOpenHelper {
if (ignoreField(field)) { if (ignoreField(field)) {
continue; continue;
} }
sb.append(field.getName());
Class<?> type = field.getType(); Class<?> type = field.getType();
if (type == String.class) { sb.append(field.getName());
if (type == String.class
|| type == Map.class
|| type == List.class
|| isOneToOne(field)
|| type.isEnum()) {
sb.append(" varchar"); sb.append(" varchar");
} else if (type == int.class || type == Integer.class) { } else if (type == int.class || type == Integer.class) {
sb.append(" interger"); sb.append(" interger");
@ -401,6 +554,10 @@ final class SqlHelper extends SQLiteOpenHelper {
} else { } else {
continue; continue;
} }
if (isPrimary(field)) {
//sb.append(" PRIMARY KEY");
sb.append(" NOT NULL");
}
sb.append(","); sb.append(",");
} }
String str = sb.toString(); String str = sb.toString();
@ -447,8 +604,8 @@ final class SqlHelper extends SQLiteOpenHelper {
/** /**
* 根据数据游标创建一个具体的对象 * 根据数据游标创建一个具体的对象
*/ */
static synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz, private static synchronized <T extends DbEntity> List<T> newInstanceEntity(SQLiteDatabase db,
Cursor cursor) { Class<T> clazz, Cursor cursor) {
List<Field> fields = CommonUtil.getAllFields(clazz); List<Field> fields = CommonUtil.getAllFields(clazz);
List<T> entitys = new ArrayList<>(); List<T> entitys = new ArrayList<>();
if (fields != null && fields.size() > 0) { if (fields != null && fields.size() > 0) {
@ -479,8 +636,39 @@ final class SqlHelper extends SQLiteOpenHelper {
field.set(entity, new Date(cursor.getString(column))); field.set(entity, new Date(cursor.getString(column)));
} else if (type == byte[].class) { } else if (type == byte[].class) {
field.set(entity, cursor.getBlob(column)); field.set(entity, cursor.getBlob(column));
} else if (type == Map.class) {
field.set(entity, str2Map(cursor.getString(column)));
} else if (type == List.class) {
String value = cursor.getString(column);
if (isOneToMany(field)) {
//主键字段
String primaryKey = getPrimaryName(clazz);
if (TextUtils.isEmpty(primaryKey)) {
throw new IllegalArgumentException("List中的元素对象必须需要@Primary注解的字段");
}
//list字段保存的数据
int kc = cursor.getColumnIndex(primaryKey);
String primaryData = cursor.getString(kc);
if (TextUtils.isEmpty(primaryData)) continue;
List<T> list = findForeignData(db, primaryData, value);
if (list == null) continue;
field.set(entity, findForeignData(db, primaryData, value));
} else { } else {
continue; field.set(entity, str2List(value, field));
}
} else if (isOneToOne(field)) {
String primaryKey = getPrimaryName(clazz);
if (TextUtils.isEmpty(primaryKey)) {
throw new IllegalArgumentException("@OneToOne的注解对象必须需要@Primary注解的字段");
}
int kc = cursor.getColumnIndex(primaryKey);
String params = cursor.getString(column);
String primaryData = cursor.getString(kc);
if (TextUtils.isEmpty(primaryData) || primaryData.equalsIgnoreCase("null")) continue;
List<T> list = findForeignData(db, primaryData, params);
if (list != null && list.size() > 0) {
field.set(entity, list.get(0));
}
} }
} }
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid")); entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
@ -496,6 +684,53 @@ final class SqlHelper extends SQLiteOpenHelper {
return entitys; return entitys;
} }
/**
* 查找一对多一对一的关联数据
*
* @param primary 当前表的主键
* @param childParams 当前表关联数据的类名 $$ 主键名
*/
private static <T extends DbEntity> List<T> findForeignData(SQLiteDatabase db, String primary,
String childParams) {
String[] params = childParams.split("\\$\\$");
return findData(db, params[0], params[1] + "=?", primary);
}
/**
* 字符串转Map只支持
* <pre>
* {@code Map<String, String>}
* </pre>
*/
private static Map<String, String> str2Map(String str) {
Map<String, String> map = new HashMap<>();
if (TextUtils.isEmpty(str)) {
return map;
}
String[] element = str.split(",");
for (String data : element) {
String[] s = data.split("\\$");
map.put(s[0], s[1]);
}
return map;
}
/**
* Map转字符串只支持
* <pre>
* {@code Map<String, String>}
* </pre>
*/
static String map2Str(Map<String, String> map) {
StringBuilder sb = new StringBuilder();
Set<String> keys = map.keySet();
for (String key : keys) {
sb.append(key).append("$").append(map.get(key)).append(",");
}
String str = sb.toString();
return TextUtils.isEmpty(str) ? str : str.substring(0, str.length() - 1);
}
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();
} }
@ -511,7 +746,7 @@ final class SqlHelper extends SQLiteOpenHelper {
* @return true 忽略该字段 * @return true 忽略该字段
*/ */
static boolean ignoreField(Field field) { static boolean ignoreField(Field field) {
// field.isSynthetic(), 使用as热启动App时,AS会自动给你的clss添加change字段 // field.isSynthetic(), 使用as热启动App时,AS会自动给你的class添加change字段
Ignore ignore = field.getAnnotation(Ignore.class); Ignore ignore = field.getAnnotation(Ignore.class);
int modifiers = field.getModifiers(); int modifiers = field.getModifiers();
return (ignore != null && ignore.value()) return (ignore != null && ignore.value())
@ -520,4 +755,28 @@ final class SqlHelper extends SQLiteOpenHelper {
|| Modifier.isStatic(modifiers) || Modifier.isStatic(modifiers)
|| Modifier.isFinal(modifiers); || Modifier.isFinal(modifiers);
} }
/**
* 判断是否一对多注解
*/
static boolean isOneToMany(Field field) {
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
return oneToMany != null;
}
/**
* 判断是否是一对一注解
*/
static boolean isOneToOne(Field field) {
OneToOne oneToOne = field.getAnnotation(OneToOne.class);
return oneToOne != null;
}
/**
* 判断是否是主键
*/
static boolean isPrimary(Field field) {
Primary pk = field.getAnnotation(Primary.class);
return pk != null;
}
} }

@ -24,6 +24,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity; import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity; import com.arialyy.aria.core.upload.UploadTaskEntity;
import com.arialyy.aria.exception.FileException; import com.arialyy.aria.exception.FileException;
import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -76,6 +77,24 @@ public class CheckUtil {
if (TextUtils.isEmpty(downloadUrl)) throw new IllegalArgumentException("下载链接不能为null"); if (TextUtils.isEmpty(downloadUrl)) throw new IllegalArgumentException("下载链接不能为null");
} }
/**
* 检测下载链接组是否为null
*/
public static void checkDownloadUrls(List<String> urls) {
if (urls == null || urls.isEmpty()) {
throw new IllegalArgumentException("链接组不能为null");
}
}
/**
* 检查下载任务组保存路径
*/
public static void checkDownloadPaths(List<String> paths) {
if (paths == null || paths.isEmpty()) {
throw new IllegalArgumentException("链接保存路径不能为null");
}
}
/** /**
* 检测上传地址是否为null * 检测上传地址是否为null
*/ */
@ -88,9 +107,9 @@ public class CheckUtil {
*/ */
public static void checkTaskEntity(AbsTaskEntity entity) { public static void checkTaskEntity(AbsTaskEntity entity) {
if (entity instanceof DownloadTaskEntity) { if (entity instanceof DownloadTaskEntity) {
checkDownloadTaskEntity(((DownloadTaskEntity) entity).downloadEntity); checkDownloadTaskEntity(((DownloadTaskEntity) entity).getEntity());
} else if (entity instanceof UploadTaskEntity) { } else if (entity instanceof UploadTaskEntity) {
checkUploadTaskEntity(((UploadTaskEntity) entity).uploadEntity); checkUploadTaskEntity(((UploadTaskEntity) entity).getEntity());
} }
} }
@ -103,7 +122,7 @@ public class CheckUtil {
public static boolean checkCmdEntity(AbsTaskEntity entity, boolean checkType) { public static boolean checkCmdEntity(AbsTaskEntity entity, boolean checkType) {
boolean b = false; boolean b = false;
if (entity instanceof DownloadTaskEntity) { if (entity instanceof DownloadTaskEntity) {
DownloadEntity entity1 = ((DownloadTaskEntity) entity).downloadEntity; DownloadEntity entity1 = ((DownloadTaskEntity) entity).getEntity();
if (entity1 == null) { if (entity1 == null) {
Log.e(TAG, "下载实体不能为空"); Log.e(TAG, "下载实体不能为空");
} else if (checkType && TextUtils.isEmpty(entity1.getDownloadUrl())) { } else if (checkType && TextUtils.isEmpty(entity1.getDownloadUrl())) {
@ -114,7 +133,7 @@ public class CheckUtil {
b = true; b = true;
} }
} else if (entity instanceof UploadTaskEntity) { } else if (entity instanceof UploadTaskEntity) {
UploadEntity entity1 = ((UploadTaskEntity) entity).uploadEntity; UploadEntity entity1 = ((UploadTaskEntity) entity).getEntity();
if (entity1 == null) { if (entity1 == null) {
Log.e(TAG, "上传实体不能为空"); Log.e(TAG, "上传实体不能为空");
} else if (TextUtils.isEmpty(entity1.getFilePath())) { } else if (TextUtils.isEmpty(entity1.getFilePath())) {

@ -22,9 +22,14 @@ import android.content.SharedPreferences;
import android.net.Uri; import android.net.Uri;
import android.text.TextUtils; import android.text.TextUtils;
import android.util.Log; import android.util.Log;
import com.arialyy.aria.core.command.CmdFactory; import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.AbsCmd; import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.command.normal.AbsNormalCmd;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity; import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTaskEntity;
import java.io.File; import java.io.File;
import java.io.FileFilter; import java.io.FileFilter;
import java.io.FileInputStream; import java.io.FileInputStream;
@ -42,6 +47,11 @@ import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
/** /**
* Created by lyy on 2016/1/22. * Created by lyy on 2016/1/22.
@ -49,10 +59,140 @@ import java.util.regex.Pattern;
public class CommonUtil { public class CommonUtil {
private static final String TAG = "CommonUtil"; private static final String TAG = "CommonUtil";
/**
* 实例化泛型的实际类型参数
*
* @throws Exception
*/
public static void typeCheck(Type type) throws Exception {
System.out.println("该类型是" + type);
// 参数化类型
if (type instanceof ParameterizedType) {
Type[] typeArguments = ((ParameterizedType) type).getActualTypeArguments();
for (int i = 0; i < typeArguments.length; i++) {
// 类型变量
if (typeArguments[i] instanceof TypeVariable) {
System.out.println("第" + (i + 1) + "个泛型参数类型是类型变量" + typeArguments[i] + ",无法实例化。");
}
// 通配符表达式
else if (typeArguments[i] instanceof WildcardType) {
System.out.println("第" + (i + 1) + "个泛型参数类型是通配符表达式" + typeArguments[i] + ",无法实例化。");
}
// 泛型的实际类型,即实际存在的类型
else if (typeArguments[i] instanceof Class) {
System.out.println("第" + (i + 1) + "个泛型参数类型是:" + typeArguments[i] + ",可以直接实例化对象");
}
}
// 参数化类型数组或类型变量数组
} else if (type instanceof GenericArrayType) {
System.out.println("该泛型类型是参数化类型数组或类型变量数组,可以获取其原始类型。");
Type componentType = ((GenericArrayType) type).getGenericComponentType();
// 类型变量
if (componentType instanceof TypeVariable) {
System.out.println("该类型变量数组的原始类型是类型变量" + componentType + ",无法实例化。");
}
// 参数化类型,参数化类型数组或类型变量数组
// 参数化类型数组或类型变量数组也可以是多维的数组,getGenericComponentType()方法仅仅是去掉最右边的[]
else {
// 递归调用方法自身
typeCheck(componentType);
}
} else if (type instanceof TypeVariable) {
System.out.println("该类型是类型变量");
} else if (type instanceof WildcardType) {
System.out.println("该类型是通配符表达式");
} else if (type instanceof Class) {
System.out.println("该类型不是泛型类型");
} else {
throw new Exception();
}
}
/**
* 根据下载任务组的url创建key
*
* @return urls null 或者 size为0返回""
*/
public static String getMd5Code(List<String> urls) {
if (urls == null || urls.size() < 1) return "";
String md5 = "";
StringBuilder sb = new StringBuilder();
for (String url : urls) {
sb.append(url);
}
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(sb.toString().getBytes());
md5 = new BigInteger(1, md.digest()).toString(16);
} catch (NoSuchAlgorithmException e) {
Log.e(TAG, e.getMessage());
}
return md5;
}
/**
* 删除上传任务的配置包括
*
* @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经下载完成的文件
* {@code false}如果任务已经完成只删除任务数据库记录
*/
public static void delUploadTaskConfig(boolean removeFile, UploadTaskEntity tEntity) {
UploadEntity uEntity = tEntity.getEntity();
File file = new File(uEntity.getFilePath());
if (removeFile) {
if (file.exists()) {
file.delete();
}
} else {
if (!uEntity.isComplete()) {
if (file.exists()) {
file.delete();
}
}
}
File config = new File(
AriaManager.APP.getFilesDir().getPath() + "/temp/" + uEntity.getFileName() + ".properties");
if (config.exists()) {
config.delete();
}
uEntity.deleteData();
tEntity.deleteData();
}
/**
* 删除下载任务的配置包括
*
* @param removeFile {@code true} 不仅删除任务数据库记录还会删除已经下载完成的文件
* {@code false}如果任务已经完成只删除任务数据库记录
*/
public static void delDownloadTaskConfig(boolean removeFile, DownloadTaskEntity tEntity) {
DownloadEntity dEntity = tEntity.getEntity();
File file = new File(dEntity.getDownloadPath());
if (removeFile) {
if (file.exists()) {
file.delete();
}
} else {
if (!dEntity.isComplete()) {
if (file.exists()) {
file.delete();
}
}
}
File config = new File(
AriaManager.APP.getFilesDir().getPath() + "/temp/" + dEntity.getFileName() + ".properties");
if (config.exists()) {
config.delete();
}
dEntity.deleteData();
tEntity.deleteData();
}
/** /**
* 获取CPU核心数 * 获取CPU核心数
*/ */
public static int getNumCores() { public static int getCoresNum() {
//Private Class to display only CPU devices in the directory listing //Private Class to display only CPU devices in the directory listing
class CpuFilter implements FileFilter { class CpuFilter implements FileFilter {
@Override public boolean accept(File pathname) { @Override public boolean accept(File pathname) {
@ -180,8 +320,8 @@ public class CommonUtil {
} }
} }
public static <T extends AbsTaskEntity> AbsCmd createCmd(String target, T entity, int cmd) { public static <T extends AbsTaskEntity> AbsNormalCmd createCmd(String target, T entity, int cmd) {
return CmdFactory.getInstance().createCmd(target, entity, cmd); return NormalCmdFactory.getInstance().createCmd(target, entity, cmd);
} }
/** /**
@ -230,6 +370,10 @@ public class CommonUtil {
List<Field> fields = new ArrayList<>(); List<Field> fields = new ArrayList<>();
Class personClazz = clazz.getSuperclass(); Class personClazz = clazz.getSuperclass();
if (personClazz != null) { if (personClazz != null) {
Class rootClazz = personClazz.getSuperclass();
if (rootClazz != null) {
Collections.addAll(fields, rootClazz.getDeclaredFields());
}
Collections.addAll(fields, personClazz.getDeclaredFields()); Collections.addAll(fields, personClazz.getDeclaredFields());
} }
Collections.addAll(fields, clazz.getDeclaredFields()); Collections.addAll(fields, clazz.getDeclaredFields());
@ -397,9 +541,11 @@ public class CommonUtil {
} }
/** /**
* 创建文件 当文件不存在的时候就创建一个文件否则直接返回文件 * 创建文件
* 当文件不存在的时候就创建一个文件
* 如果文件存在先删除原文件然后重新创建一个新文件
*/ */
public static File createFile(String path) { public static void createFile(String path) {
File file = new File(path); File file = new File(path);
if (!file.getParentFile().exists()) { if (!file.getParentFile().exists()) {
Log.d(TAG, "目标文件所在路径不存在,准备创建……"); Log.d(TAG, "目标文件所在路径不存在,准备创建……");
@ -408,19 +554,18 @@ public class CommonUtil {
} }
} }
// 创建目标文件 // 创建目标文件
if (file.exists()) {
final File to = new File(file.getAbsolutePath() + System.currentTimeMillis());
file.renameTo(to);
to.delete();
}
try { try {
if (!file.exists()) {
if (file.createNewFile()) { if (file.createNewFile()) {
Log.d(TAG, "创建文件成功:" + file.getAbsolutePath()); Log.d(TAG, "创建文件成功:" + file.getAbsolutePath());
} }
return file;
} else {
return file;
}
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
return null;
} }
/** /**

@ -1,14 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<ListView
android:id="@+id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>

@ -1,51 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
>
<CheckBox
android:id="@+id/checkbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:clickable="false"
/>
<ImageView
android:id="@+id/img"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerVertical="true"
/>
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignTop="@+id/img"
android:layout_marginLeft="10dp"
android:layout_marginRight="5dp"
android:layout_toLeftOf="@+id/checkbox"
android:layout_toRightOf="@+id/img"
android:ellipsize="end"
android:maxLines="1"
android:textSize="18sp"
android:textStyle="bold"
/>
<TextView
android:id="@+id/info"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/title"
android:layout_below="@+id/title"
android:layout_marginRight="5dp"
android:layout_marginTop="10dp"
android:layout_toLeftOf="@+id/checkbox"
/>
</RelativeLayout>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save