pull/330/head
AriaLyy 8 years ago
commit ce886921a6
  1. 6
      Aria/build.gradle
  2. 56
      Aria/src/main/java/com/arialyy/aria/core/Aria.java
  3. 3
      Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
  4. 13
      Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java
  5. 6
      Aria/src/main/java/com/arialyy/aria/core/QueueMod.java
  6. 46
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java
  7. 30
      Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java
  8. 4
      Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java
  9. 46
      Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java
  10. 35
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java
  11. 71
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java
  12. 72
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java
  13. 35
      Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java
  14. 56
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java
  15. 9
      Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java
  16. 67
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java
  17. 9
      Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java
  18. 16
      Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java
  19. 22
      Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java
  20. 15
      Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java
  21. 45
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java
  22. 4
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java
  23. 8
      Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java
  24. 47
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java
  25. 67
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java
  26. 24
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java
  27. 73
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java
  28. 205
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java
  29. 31
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java
  30. 72
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java
  31. 77
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java
  32. 106
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTask.java
  33. 12
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java
  34. 496
      Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java
  35. 24
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java
  36. 3
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java
  37. 312
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java
  38. 5
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java
  39. 99
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java
  40. 376
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java
  41. 161
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java
  42. 4
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java
  43. 24
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java
  44. 10
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java
  45. 6
      Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java
  46. 33
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java
  47. 71
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java
  48. 25
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java
  49. 31
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java
  50. 73
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java
  51. 106
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java
  52. 48
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java
  53. 27
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java
  54. 199
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java
  55. 146
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java
  56. 27
      Aria/src/main/java/com/arialyy/aria/core/inf/AbsTaskEntity.java
  57. 2
      Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java
  58. 86
      Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java
  59. 17
      Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java
  60. 86
      Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java
  61. 71
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadGroupTaskQueue.java
  62. 64
      Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java
  63. 12
      Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java
  64. 32
      Aria/src/main/java/com/arialyy/aria/core/queue/TaskFactory.java
  65. 26
      Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java
  66. 8
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseCachePool.java
  67. 28
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java
  68. 82
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java
  69. 14
      Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java
  70. 13
      Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java
  71. 45
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadGroupSchedulers.java
  72. 2
      Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java
  73. 7
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java
  74. 41
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java
  75. 63
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java
  76. 6
      Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java
  77. 10
      Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java
  78. 15
      Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java
  79. 36
      Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java
  80. 38
      Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java
  81. 2
      Aria/src/main/java/com/arialyy/aria/orm/Primary.java
  82. 261
      Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
  83. 27
      Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
  84. 131
      Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
  85. 2
      AriaAnnotations/build.gradle
  86. 2
      AriaCompiler/build.gradle
  87. 3
      app/build.gradle
  88. 5
      app/src/main/assets/aria_config.xml
  89. 65
      app/src/main/java/com/arialyy/simple/download/DownloadModule.java
  90. 12
      app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java
  91. 5
      app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java
  92. 19
      aria/src/main/java/com/arialyy/aria/core/Configuration.java
  93. 82
      aria/src/main/java/com/arialyy/aria/core/upload/UploadTask.java
  94. 13
      aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java
  95. 6
      build.gradle

@ -22,8 +22,8 @@ dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
compile project(':AriaCompiler')
// compile project(':AriaAnnotations')
// compile project(':AriaCompiler')
compile project(':AriaAnnotations')
}
//apply from: 'bintray-release.gradle'
apply from: 'bintray-release.gradle'
//apply from: 'jcenter.gradle'

@ -59,62 +59,6 @@ import com.arialyy.aria.core.upload.UploadTask;
* </pre>
*/
@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() {
}

@ -29,14 +29,13 @@ import android.text.TextUtils;
import android.util.Log;
import android.widget.PopupWindow;
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.upload.UploadReceiver;
import com.arialyy.aria.orm.DbUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;

@ -54,9 +54,6 @@ class ConfigHelper extends DefaultHandler {
case "threadNum":
loadThreadNum(value);
break;
case "openBroadcast":
loadBroadcast(value);
break;
case "maxTaskNum":
loadMaxQueue(value);
break;
@ -224,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) {
int num = 3;
if (!TextUtils.isEmpty(value)) {

@ -6,8 +6,10 @@ package com.arialyy.aria.core;
*/
public enum QueueMod {
/**
* 等待模式如果执行队列已经满了再次使用start命令执行任务时该任务会被添加到缓存队列中
* 当执行队列的任务完成时将自动执行缓存队列中的任务
* 等待模式
* 如果执行队列已经满了再对其它任务TASK_A使用start命令执行任务时
* 1TASK_A添加到缓存队列中当执行队列中的任务完成时系统会将自动执行缓存队列中的TASK_A
* 2如果再次对TASK_A使用start命令TASK_A将会立刻执行
*/
WAIT("wait"),

@ -16,50 +16,20 @@
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.queue.DownloadTaskQueue;
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 {
ITaskQueue mQueue;
T mTaskEntity;
String TAG;
String mTargetName;
/**
* 能否执行命令
*/
boolean canExeCmd = true;
public abstract class AbsCmd<T extends AbsTaskEntity> implements ICmd{
protected ITaskQueue mQueue;
protected T mTaskEntity;
protected String TAG;
protected String mTargetName;
/**
* 是否是下载任务的命令
* {@code true} 下载任务的命令{@code false} 上传任务的命令
*/
boolean isDownloadCmd = true;
/**
* @param targetName 产生任务的对象名
*/
AbsCmd(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;
}
}
}
protected boolean isDownloadCmd = true;
}

@ -0,0 +1,30 @@
/*
* 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
* limitations under the License.
*/
package com.arialyy.aria.core.inf;
package com.arialyy.aria.core.command;
/**
* 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.
* 任务组命令
*/
public 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;
}
}
}

@ -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 GroupCancelCmd<T extends AbsTaskEntity> extends AbsGroupCmd<T> {
/**
* @param targetName 创建任务的对象名
*/
GroupCancelCmd(String targetName, T entity) {
super(targetName, entity);
}
@Override public void executeCmd() {
}
}

@ -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.
*/
public 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.getExePoolSize() < 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,56 @@
/*
* 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.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
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;
}
}
}

@ -14,18 +14,19 @@
* limitations under the License.
*/
package com.arialyy.aria.core.command;
package com.arialyy.aria.core.command.normal;
import android.util.Log;
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.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* 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) {
super(targetName, entity);
@ -33,7 +34,7 @@ class AddCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
@Override public void executeCmd() {
if (!canExeCmd) return;
ITask task = mQueue.getTask(mTaskEntity.getEntity());
AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
if (task == null) {
mTaskEntity.getEntity().setState(IEntity.STATE_WAIT);
mQueue.createTask(mTargetName, mTaskEntity);

@ -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.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
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<UploadEntity> allEntity = DbEntity.findAllData(UploadEntity.class);
for (UploadEntity entity : allEntity) {
CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, entity);
}
}
/**
* 处理下载的删除
*/
private void handleDownloadRemove() {
List<DownloadEntity> allEntity = DbEntity.findAllData(DownloadEntity.class);
for (DownloadEntity entity : allEntity) {
CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, entity);
}
}
}

@ -14,24 +14,25 @@
* limitations under the License.
*/
package com.arialyy.aria.core.command;
package com.arialyy.aria.core.command.normal;
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;
/**
* 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) {
super(targetName, entity);
}
@Override public void executeCmd() {
if (!canExeCmd) return;
ITask task = mQueue.getTask(mTaskEntity.getEntity());
AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
if (task == null) {
task = mQueue.createTask(mTargetName, mTaskEntity);
}

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

@ -14,16 +14,17 @@
* 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.command.AbsCmdFactory;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* 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_CANCEL_ALL = 0x131;
private static volatile NormalCmdFactory INSTANCE = null;
private static volatile CmdFactory INSTANCE = null;
private CmdFactory() {
private NormalCmdFactory() {
}
public static CmdFactory getInstance() {
public static NormalCmdFactory getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new CmdFactory();
INSTANCE = new NormalCmdFactory();
}
}
return INSTANCE;
@ -78,7 +82,7 @@ public class CmdFactory {
* @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}
*/
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) {
case TASK_CREATE:
return new AddCmd<>(target, entity);
@ -95,6 +99,8 @@ public class CmdFactory {
return new StopAllCmd<>(target, entity);
case TASK_RESUME_ALL:
return new ResumeAllCmd<>(target, entity);
case TASK_CANCEL_ALL:
return new CancelAllCmd<>(target, entity);
default:
return null;
}

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

@ -14,19 +14,21 @@
* limitations under the License.
*/
package com.arialyy.aria.core.command;
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.inf.ITask;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* Created by lyy on 2016/8/22.
* 开始命令
* 队列模型{@link QueueMod#NOW}{@link QueueMod#WAIT}
*/
class StartCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
class StartCmd<T extends AbsTaskEntity> extends AbsNormalCmd<T> {
StartCmd(String targetName, T entity) {
super(targetName, entity);
@ -34,31 +36,38 @@ class StartCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
@Override public void executeCmd() {
if (!canExeCmd) return;
ITask task = mQueue.getTask(mTaskEntity.getEntity());
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 (task != null) {
if (!TextUtils.isEmpty(mTargetName)) {
task.setTargetName(mTargetName);
}
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();
}
// 任务不存在时,根据配置不同,对任务执行操作
if (mod.equals(QueueMod.NOW.getTag())) {
mQueue.startTask(task);
}else if (mod.equals(QueueMod.WAIT.getTag())){
if (mQueue.getExePoolSize() < maxTaskNum){
} else if (mod.equals(QueueMod.WAIT.getTag())) {
if (mQueue.getExePoolSize() < maxTaskNum) {
mQueue.startTask(task);
}
}
} else {
// 任务不存在时,根据配置不同,对任务执行操作
if (!task.isRunning()
&& mod.equals(QueueMod.WAIT.getTag())
&& task.getState() == IEntity.STATE_WAIT) {
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;
@ -6,7 +6,7 @@ import com.arialyy.aria.core.inf.AbsTaskEntity;
* 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 产生任务的对象名
*/

@ -14,19 +14,19 @@
* limitations under the License.
*/
package com.arialyy.aria.core.command;
package com.arialyy.aria.core.command.normal;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
/**
* 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) {
super(targetName, entity);
@ -34,7 +34,7 @@ class StopCmd<T extends AbsTaskEntity> extends AbsCmd<T> {
@Override public void executeCmd() {
if (!canExeCmd) return;
ITask task = mQueue.getTask(mTaskEntity.getEntity());
AbsTask task = mQueue.getTask(mTaskEntity.getEntity());
if (task == null) {
if (mTaskEntity.getEntity().getState() == IEntity.STATE_RUNNING) {
task = mQueue.createTask(mTargetName, mTaskEntity);

@ -18,25 +18,35 @@ package com.arialyy.aria.core.download;
import android.os.Parcel;
import android.os.Parcelable;
import com.arialyy.aria.core.inf.AbsEntity;
import com.arialyy.aria.orm.Ignore;
import com.arialyy.aria.core.inf.AbsNormalEntity;
import com.arialyy.aria.orm.Primary;
/**
* Created by lyy on 2015/12/25.
* 下载实体
* 注意CREATOR要进行@Ignore注解
* 并且需要Parcelable时需要手动填写rowID;
*/
public class DownloadEntity extends AbsEntity implements Parcelable {
private String downloadUrl = ""; //下载路径
public class DownloadEntity extends AbsNormalEntity implements Parcelable {
@Primary private String downloadUrl = ""; //下载路径
private String downloadPath = ""; //保存路径
private boolean isDownloadComplete = false; //是否下载完成
private boolean isRedirect = false; //是否重定向
private String redirectUrl = ""; //重定向链接
/**
* 所属任务组
*/
private String groupName = "";
public DownloadEntity() {
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
public String getDownloadUrl() {
return downloadUrl;
@ -95,6 +105,7 @@ public class DownloadEntity extends AbsEntity implements Parcelable {
dest.writeByte(this.isDownloadComplete ? (byte) 1 : (byte) 0);
dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0);
dest.writeString(this.redirectUrl);
dest.writeString(this.groupName);
}
protected DownloadEntity(Parcel in) {
@ -104,9 +115,31 @@ public class DownloadEntity extends AbsEntity implements Parcelable {
this.isDownloadComplete = in.readByte() != 0;
this.isRedirect = in.readByte() != 0;
this.redirectUrl = in.readString();
this.groupName = in.readString();
}
@Override public String toString() {
return "DownloadEntity{"
+ "downloadUrl='"
+ downloadUrl
+ '\''
+ ", downloadPath='"
+ downloadPath
+ '\''
+ ", isDownloadComplete="
+ isDownloadComplete
+ ", isRedirect="
+ isRedirect
+ ", redirectUrl='"
+ redirectUrl
+ '\''
+ ", groupName='"
+ groupName
+ '\''
+ '}';
}
@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) {
return new DownloadEntity(source);
}

@ -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.download;
import android.os.Parcel;
import com.arialyy.aria.core.inf.AbsGroupEntity;
import com.arialyy.aria.orm.OneToMany;
import java.util.LinkedList;
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> mChild = new LinkedList<>();
public List<DownloadEntity> getChild() {
return mChild;
}
public void setChild(List<DownloadEntity> child) {
this.mChild = child;
}
@Override public int describeContents() {
return 0;
}
@Override public void writeToParcel(Parcel dest, int flags) {
super.writeToParcel(dest, flags);
dest.writeTypedList(this.mChild);
}
public DownloadGroupEntity() {
}
protected DownloadGroupEntity(Parcel in) {
super(in);
this.mChild = in.createTypedArrayList(DownloadEntity.CREATOR);
}
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,24 @@
/*
* 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;
/**
* Created by AriaL on 2017/6/30.
*/
public class DownloadGroupListener {
}

@ -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.download;
import com.arialyy.aria.core.inf.AbsGroupTarget;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.util.CheckUtil;
import java.io.File;
import java.util.List;
/**
* Created by AriaL on 2017/6/29.
*/
public class DownloadGroupTarget
extends AbsGroupTarget<DownloadGroupTarget, DownloadGroupEntity, DownloadGroupTaskEntity> {
private List<String> mUrls;
DownloadGroupTarget(DownloadGroupEntity entity, String targetName, List<String> urls) {
this.mEntity = entity;
this.mTargetName = targetName;
this.mUrls = urls;
mTaskEntity = new DownloadGroupTaskEntity();
mTaskEntity.entity = entity;
}
/**
* 设置保存路径组
*/
public DownloadGroupTarget setDownloadPaths(List<String> paths) {
CheckUtil.checkDownloadPaths(paths);
if (mUrls.size() != paths.size()) {
throw new IllegalArgumentException("下载链接数必须要和保存路径的数量一致");
}
for (int i = 0, len = mUrls.size(); i < len; i++) {
mTaskEntity.getEntity().getChild().add(createDownloadEntity(mUrls.get(i), paths.get(i)));
}
return this;
}
/**
* 创建子任务下载实体
*
* @param url 下载地址
* @param path 保存路径
*/
private DownloadEntity createDownloadEntity(String url, String path) {
DownloadEntity entity = DownloadEntity.findData(DownloadEntity.class, "downloadUrl=?", url);
if (entity == null) {
entity = new DownloadEntity();
}
File file = new File(path);
if (!file.exists()) {
entity.setState(IEntity.STATE_WAIT);
}
entity.setDownloadPath(path);
entity.setDownloadUrl(url);
entity.setFileName(file.getName());
return entity;
}
}

@ -0,0 +1,205 @@
/*
* 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.os.Handler;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.downloader.DownloadGroupUtil;
import com.arialyy.aria.core.download.downloader.DownloadListener;
import com.arialyy.aria.core.download.downloader.IDownloadUtil;
import com.arialyy.aria.core.inf.AbsGroupTask;
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.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.lang.ref.WeakReference;
/**
* Created by AriaL on 2017/6/27.
* 任务组任务
*/
public class DownloadGroupTask extends AbsGroupTask<DownloadGroupTaskEntity, DownloadGroupEntity> {
private DListener mListener;
private IDownloadUtil mUtil;
private DownloadGroupTask(DownloadGroupTaskEntity taskEntity, Handler outHandler) {
mTaskEntity = taskEntity;
mEntity = taskEntity.getEntity();
mOutHandler = outHandler;
mContext = AriaManager.APP;
mListener = new DListener(mContext, this, mOutHandler);
mUtil = new DownloadGroupUtil(mListener, mTaskEntity);
}
@Override public boolean isRunning() {
return mUtil.isDownloading();
}
@Override public void start() {
mUtil.stopDownload();
}
@Override public void stop() {
mUtil.startDownload();
}
@Override public void cancel() {
mUtil.cancelDownload();
}
/**
* 下载监听类
*/
private static class DListener extends DownloadListener {
WeakReference<Handler> outHandler;
WeakReference<DownloadGroupTask> wTask;
Context context;
long lastLen = 0; //上一次发送长度
boolean isFirst = true;
DownloadGroupEntity entity;
DownloadGroupTask task;
boolean isConvertSpeed = false;
DListener(Context context, DownloadGroupTask task, Handler outHandler) {
this.context = context;
this.outHandler = new WeakReference<>(outHandler);
this.wTask = new WeakReference<>(task);
this.task = wTask.get();
this.entity = this.task.getEntity();
final AriaManager manager = AriaManager.getInstance(context);
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);
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) {
long speed = currentLocation - lastLen;
if (isFirst) {
speed = 0;
isFirst = false;
}
handleSpeed(speed);
lastLen = currentLocation;
sendInState2Target(ISchedulers.RUNNING);
}
@Override public void onStop(long stopLocation) {
saveData(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 DownloadSchedulers#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 {
entity.setState(state);
if (location != -1) {
entity.setCurrentProgress(location);
}
entity.update();
}
}
}
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,17 +17,16 @@ package com.arialyy.aria.core.download;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.AriaManager;
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.command.CmdFactory;
import com.arialyy.aria.core.command.AbsCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulerListener;
import com.arialyy.aria.orm.DbEntity;
import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
@ -35,10 +34,8 @@ import java.util.Set;
* Created by lyy on 2016/12/5.
* 下载功能接收器
*/
public class DownloadReceiver implements IReceiver<DownloadEntity> {
private static final String TAG = "DownloadReceiver";
public String targetName;
public Object obj;
public class DownloadReceiver extends AbsReceiver<DownloadEntity> {
private final String TAG = "DownloadReceiver";
public ISchedulerListener<DownloadTask> listener;
/**
@ -77,15 +74,17 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
}
/**
* 添加调度器回调
*
* @see #register()
* 加载下载地址如果任务组的中的下载地址改变了则任务从新的一个任务组
*/
@Deprecated public DownloadReceiver addSchedulerListener(
ISchedulerListener<DownloadTask> listener) {
this.listener = listener;
DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener);
return this;
public DownloadGroupTarget load(List<String> urls) {
CheckUtil.checkDownloadUrls(urls);
DownloadGroupEntity entity =
DbEntity.findData(DownloadGroupEntity.class, "urlHash=?", CommonUtil.getMd5Code(urls));
if (entity == null) {
entity = new DownloadGroupEntity();
}
return new DownloadGroupTarget(entity, targetName, urls);
}
/**
@ -103,6 +102,18 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
DownloadSchedulers.getInstance().unRegister(obj);
}
/**
* 添加调度器回调
*
* @see #register()
*/
@Deprecated public DownloadReceiver addSchedulerListener(
ISchedulerListener<DownloadTask> listener) {
this.listener = listener;
DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener);
return this;
}
/**
* 移除回调
*
@ -142,9 +153,10 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
* 停止所有正在下载的任务并清空等待队列
*/
@Override public void stopAllTask() {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
ariaManager.setCmd(CmdFactory.getInstance()
.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_STOP_ALL)).exe();
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_STOP_ALL))
.exe();
}
/**
@ -153,23 +165,25 @@ public class DownloadReceiver implements IReceiver<DownloadEntity> {
* 2.如果队列执行队列已经满了则将所有任务添加到等待队列中
*/
public void resumeAllTask() {
final AriaManager ariaManager = AriaManager.getInstance(AriaManager.APP);
ariaManager.setCmd(CmdFactory.getInstance()
.createCmd(targetName, new DownloadTaskEntity(), CmdFactory.TASK_RESUME_ALL)).exe();
AriaManager.getInstance(AriaManager.APP)
.setCmd(NormalCmdFactory.getInstance()
.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);
List<DownloadEntity> allEntity = DbEntity.findAllData(DownloadEntity.class);
List<AbsCmd> cancelCmds = new ArrayList<>();
for (DownloadEntity entity : allEntity) {
cancelCmds.add(
CommonUtil.createCmd(targetName, new DownloadTaskEntity(entity), CmdFactory.TASK_CANCEL));
}
ariaManager.setCmds(cancelCmds).exe();
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, new DownloadTaskEntity(),
NormalCmdFactory.TASK_CANCEL_ALL))
.exe();
Set<String> keys = ariaManager.getReceiver().keySet();
for (String key : keys) {
IReceiver receiver = ariaManager.getReceiver().get(key);

@ -17,31 +17,22 @@ package com.arialyy.aria.core.download;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.RequestEnum;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsNormalTarget;
import com.arialyy.aria.core.queue.DownloadTaskQueue;
import java.io.File;
import java.util.Map;
/**
* Created by lyy on 2016/12/5.
* 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) {
this.entity = entity;
this.targetName = targetName;
taskEntity = new DownloadTaskEntity(entity);
}
@Override public void pause() {
super.pause();
}
@Override public void resume() {
super.resume();
mEntity = entity;
mTargetName = targetName;
mTaskEntity = new DownloadTaskEntity();
mTaskEntity.entity = mEntity;
}
/**
@ -65,54 +56,14 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
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() {
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 +73,8 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
throw new IllegalArgumentException("文件保持路径不能为null");
}
File file = new File(downloadPath);
entity.setDownloadPath(downloadPath);
entity.setFileName(file.getName());
mEntity.setDownloadPath(downloadPath);
mEntity.setFileName(file.getName());
return this;
}
@ -136,7 +87,7 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
if (TextUtils.isEmpty(downloadName)) {
throw new IllegalArgumentException("文件名不能为null");
}
entity.setFileName(downloadName);
mEntity.setFileName(downloadName);
return this;
}
@ -147,19 +98,19 @@ public class DownloadTarget extends AbsTarget<DownloadEntity, DownloadTaskEntity
if (TextUtils.isEmpty(fileName)) {
throw new IllegalArgumentException("文件名不能为null");
}
entity.setFileName(fileName);
mEntity.setFileName(fileName);
return this;
}
private DownloadEntity getDownloadEntity() {
return entity;
return mEntity;
}
/**
* 是否在下载
*/
public boolean isDownloading() {
DownloadTask task = DownloadTaskQueue.getInstance().getTask(entity);
DownloadTask task = DownloadTaskQueue.getInstance().getTask(mEntity);
return task != null && task.isRunning();
}
}

@ -20,9 +20,11 @@ import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.util.Log;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.download.downloader.DownloadListener;
import com.arialyy.aria.core.download.downloader.DownloadUtil;
import com.arialyy.aria.core.download.downloader.IDownloadListener;
import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.CheckUtil;
@ -34,20 +36,19 @@ import java.lang.ref.WeakReference;
* 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";
private IDownloadListener mListener;
private Handler mOutHandler;
private IDownloadUtil mUtil;
private DownloadUtil mUtil;
private boolean isWait = false;
private DownloadTask(DownloadTaskEntity taskEntity, Handler outHandler) {
mEntity = taskEntity.downloadEntity;
mEntity = taskEntity.getEntity();
mOutHandler = outHandler;
mContext = AriaManager.APP;
mListener = new DListener(mContext, this, mOutHandler);
mUtil = new DownloadUtil(mContext, taskEntity, mListener);
mUtil = new DownloadUtil(taskEntity, mListener);
}
/**
@ -97,7 +98,6 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
* 暂停任务并让任务处于等待状态
*/
@Override public void stopAndWait() {
super.stopAndWait();
stop(true);
}
@ -142,11 +142,6 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
if (mOutHandler != null) {
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);
}
}
@ -159,15 +154,8 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
if (mOutHandler != null) {
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.delConfigFile();
mUtil.delTempFile();
mEntity.deleteData();
}
}
@ -195,7 +183,7 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
public DownloadTask build() {
DownloadTask task = new DownloadTask(taskEntity, outHandler);
task.setTargetName(targetName);
taskEntity.downloadEntity.save();
taskEntity.getEntity().save();
return task;
}
}
@ -207,14 +195,12 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
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;
DownloadEntity entity;
DownloadTask task;
boolean isOpenBroadCast = false;
boolean isConvertSpeed = false;
DListener(Context context, DownloadTask task, Handler outHandler) {
@ -222,110 +208,84 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
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);
this.entity = this.task.getDownloadEntity();
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);
saveData(IEntity.STATE_PRE, -1);
}
@Override public void onPostPre(long fileSize) {
super.onPostPre(fileSize);
downloadEntity.setFileSize(fileSize);
downloadEntity.setState(IEntity.STATE_POST_PRE);
entity.setFileSize(fileSize);
sendInState2Target(ISchedulers.POST_PRE);
sendIntent(Aria.ACTION_POST_PRE, -1);
saveData(IEntity.STATE_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);
saveData(IEntity.STATE_RUNNING, resumeLocation);
}
@Override public void onStart(long startLocation) {
super.onStart(startLocation);
downloadEntity.setState(IEntity.STATE_RUNNING);
sendInState2Target(ISchedulers.START);
sendIntent(Aria.ACTION_START, startLocation);
saveData(IEntity.STATE_RUNNING, 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);
entity.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);
saveData(task.isWait ? IEntity.STATE_WAIT : IEntity.STATE_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();
saveData(IEntity.STATE_CANCEL, -1);
entity.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());
saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
}
@Override public void onFail() {
super.onFail();
downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
downloadEntity.setState(IEntity.STATE_FAIL);
entity.setFailNum(entity.getFailNum() + 1);
handleSpeed(0);
sendInState2Target(ISchedulers.FAIL);
sendIntent(Aria.ACTION_FAIL, -1);
saveData(IEntity.STATE_FAIL, -1);
}
private void handleSpeed(long speed) {
if (isConvertSpeed) {
downloadEntity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
entity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
} else {
downloadEntity.setSpeed(speed);
entity.setSpeed(speed);
}
}
@ -340,17 +300,11 @@ public class DownloadTask extends AbsTask<DownloadTaskEntity, DownloadEntity> {
}
}
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);
private void saveData(int state, long location) {
entity.setState(state);
entity.setDownloadComplete(state == IEntity.STATE_COMPLETE);
entity.setCurrentProgress(location);
entity.update();
}
}
}

@ -16,22 +16,20 @@
package com.arialyy.aria.core.download;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.OneToOne;
/**
* 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 = "downloadUrl") public DownloadEntity entity;
public DownloadTaskEntity(){}
public DownloadTaskEntity(DownloadEntity downloadEntity) {
this.downloadEntity = downloadEntity;
public DownloadTaskEntity() {
}
@Override public DownloadEntity getEntity() {
return downloadEntity;
return entity;
}
}

@ -1,496 +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.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;
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()
+ "】\n"
+ 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) {
ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
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.IS_SUPPORT_BREAK_POINT = 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);
file.close();
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) {
ChildThreadConfigEntity entity = new ChildThreadConfigEntity();
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.IS_SUPPORT_BREAK_POINT = 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 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;
}
}

@ -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
* 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 java.io.IOException;
import java.net.HttpURLConnection;

@ -0,0 +1,312 @@
/*
* 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 java.io.File;
import java.util.HashMap;
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 static final String TAG = "DownloadGroupUtil";
/**
* 任务组所有任务总大小
*/
private long mTotalSize = 0;
private long mCurrentProgress = 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 mFailNum = 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<>();
public DownloadGroupUtil(IDownloadListener listener, DownloadGroupTaskEntity taskEntity) {
mListener = listener;
mTaskEntity = taskEntity;
mInfoPool = Executors.newCachedThreadPool();
mExePool = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
for (DownloadEntity entity : mTaskEntity.entity.getChild()) {
File file = new File(entity.getDownloadPath());
if (entity.isDownloadComplete() && file.exists()) {
mTotalSize += entity.getFileSize();
} else {
mExeMap.put(entity.getDownloadUrl(), createDownloadTask(entity));
}
mCurrentProgress += entity.getCurrentProgress();
}
}
@Override public long getFileSize() {
return mTotalSize;
}
@Override public long getCurrentLocation() {
return mCurrentProgress;
}
@Override public boolean isDownloading() {
return isRunning;
}
@Override public void cancelDownload() {
isRunning = false;
closeTimer();
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();
}
}
}
@Override public void stopDownload() {
isRunning = false;
closeTimer();
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();
}
/**
* 创建文件信息获取线程
*/
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 + mFailNum == mTaskEntity.getEntity().getChild().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);
}
mFailNum++;
failNum++;
if (failNum < 10) {
mInfoPool.execute(createFileInfoThread(te));
}
if (mInitNum + mFailNum == mTaskEntity.getEntity().getChild().size()) {
startRunningFlow();
}
}
};
}
return new FileInfoThread(taskEntity, callback);
}
private void closeTimer() {
if (mTimer != null) {
mTimer.purge();
mTimer.cancel();
}
}
/**
* 开始进度流程
*/
private void startRunningFlow() {
mListener.onPostPre(mTotalSize);
mListener.onStart(mCurrentProgress);
closeTimer();
mTimer = new Timer(true);
mTimer.schedule(new TimerTask() {
@Override public void run() {
mListener.onProgress(mCurrentProgress);
}
}, 1000);
}
/**
* 启动子任务下载器
*/
private void startChildDownload(DownloadTaskEntity taskEntity) {
ChildDownloadListener listener = new ChildDownloadListener(taskEntity);
Downloader dt = new Downloader(listener, taskEntity);
mDownloaderMap.put(taskEntity.getEntity().getDownloadUrl(), dt);
mExePool.execute(dt);
}
/**
* 创建子任务下载信息
*/
private DownloadTaskEntity createDownloadTask(DownloadEntity entity) {
DownloadTaskEntity taskEntity =
DbEntity.findData(DownloadTaskEntity.class, "key=?", entity.getDownloadUrl());
if (taskEntity != null) {
return taskEntity;
}
taskEntity = new DownloadTaskEntity();
taskEntity.entity = entity;
taskEntity.headers = mTaskEntity.headers;
taskEntity.requestEnum = mTaskEntity.requestEnum;
taskEntity.redirectUrlKey = mTaskEntity.redirectUrlKey;
taskEntity.removeFile = mTaskEntity.removeFile;
return taskEntity;
}
/**
* 子任务事件监听
*/
private class ChildDownloadListener extends DownloadListener {
DownloadTaskEntity taskEntity;
DownloadEntity entity;
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);
saveData(IEntity.STATE_POST_PRE, -1);
}
@Override public void onResume(long resumeLocation) {
saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
}
@Override public void onStart(long startLocation) {
saveData(IEntity.STATE_POST_PRE, IEntity.STATE_RUNNING);
}
@Override public void onProgress(long currentLocation) {
mCurrentProgress += currentLocation;
}
@Override public void onStop(long stopLocation) {
saveData(IEntity.STATE_STOP, stopLocation);
}
@Override public void onCancel() {
saveData(IEntity.STATE_CANCEL, -1);
}
@Override public void onComplete() {
saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
}
@Override public void onFail() {
entity.setFailNum(entity.getFailNum() + 1);
saveData(IEntity.STATE_FAIL, -1);
}
private void saveData(int state, long location) {
entity.setState(state);
entity.setDownloadComplete(state == IEntity.STATE_COMPLETE);
entity.setCurrentProgress(location);
entity.update();
}
}
}

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

@ -0,0 +1,99 @@
/*
* 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.Log;
import com.arialyy.aria.core.download.DownloadTaskEntity;
/**
* Created by lyy on 2015/8/25.
* 下载工具类
*/
public class DownloadUtil implements IDownloadUtil, Runnable {
private static final String TAG = "DownloadUtil";
private IDownloadListener mListener;
private Downloader mDT;
private DownloadTaskEntity mTaskEntity;
public DownloadUtil(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() {
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();
}
}

@ -0,0 +1,376 @@
/*
* 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.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;
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();
mConstance.cleanState();
mConstance.isDownloading = true;
try {
if (!mTaskEntity.isSupportBP) {
mThreadNum = 1;
handleNoSupportBreakpointDownload();
} else {
mThreadNum = isNewTask ? (mEntity.getFileSize() <= SUB_LEN ? 1
: AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum())
: mRealThreadNum;
mFixedThreadPool = Executors.newFixedThreadPool(mThreadNum);
handleBreakpoint();
}
} catch (IOException e) {
failDownload("下载失败【downloadUrl:"
+ mEntity.getDownloadUrl()
+ "】\n【filePath:"
+ mEntity.getDownloadPath()
+ "】\n"
+ CommonUtil.getPrintException(e));
}
}
@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() {
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, mEntity);
}
@Override public void stopDownload() {
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.findData(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;
mConstance.THREAD_NUM = mThreadNum;
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() throws IOException {
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) {
CommonUtil.createFile(mTempFile.getPath());
BufferedRandomAccessFile file =
new BufferedRandomAccessFile(new File(mTempFile.getPath()), "rwd", 8192);
//设置文件长度
file.setLength(fileLength);
file.close();
}
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 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;
mConstance.THREAD_NUM = mThreadNum;
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) {
Log.e(TAG, errorMsg);
mConstance.isDownloading = false;
mListener.onFail();
}
}

@ -0,0 +1,161 @@
/*
* 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.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;
/**
* 下载文件信息获取
*/
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) {
this(taskEntity, null);
}
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;
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.redirectUrlKey = conn.getHeaderField(mTaskEntity.redirectUrlKey);
mEntity.setRedirect(true);
mEntity.setRedirectUrl(mTaskEntity.redirectUrlKey);
handle302Turn(conn);
} else {
failDownload("任务【" + mEntity.getDownloadUrl() + "】下载失败,错误码:" + code);
}
if (isComplete) {
if (onFileInfoListener != null) {
onFileInfoListener.onComplete(mEntity.getDownloadUrl(), code);
}
mEntity.save();
mTaskEntity.save();
}
}
/**
* 处理30x跳转
*/
private void handle302Turn(HttpURLConnection conn) throws IOException {
String newUrl = conn.getHeaderField(mTaskEntity.redirectUrlKey);
Log.d(TAG, "30x跳转,新url为【" + newUrl + "】");
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);
}
/**
* 检查长度是否合法
*
* @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);
}
}
}

@ -14,12 +14,12 @@
* limitations under the License.
*/
package com.arialyy.aria.core.download;
package com.arialyy.aria.core.download.downloader;
/**
* 下载监听
*/
interface IDownloadListener {
public interface IDownloadListener {
/**
* 支持断点回调

@ -14,13 +14,18 @@
* limitations under the License.
*/
package com.arialyy.aria.core.download;
package com.arialyy.aria.core.download.downloader;
/**
* Created by lyy on 2016/10/31.
* 抽象的下载接口
*/
interface IDownloadUtil {
public interface IDownloadUtil {
/**
* 获取文件大小
*/
public long getFileSize();
/**
* 获取当前下载位置
@ -53,19 +58,4 @@ interface IDownloadUtil {
* 从上次断点恢复下载
*/
public void resumeDownload();
/**
* 删除下载记录文件
*/
public void delConfigFile();
/**
* 删除temp文件
*/
public void delTempFile();
/**
* 设置最大下载速度
*/
public void setMaxSpeed(double maxSpeed);
}

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.download;
package com.arialyy.aria.core.download.downloader;
import android.os.Build;
import android.text.TextUtils;
@ -36,16 +36,16 @@ import java.util.Properties;
*/
final class SingleThreadTask implements Runnable {
private static final String TAG = "SingleThreadTask";
private DownloadUtil.ChildThreadConfigEntity mConfigEntity;
private ChildThreadConfigEntity mConfigEntity;
private String mConfigFPath;
private long mChildCurrentLocation = 0;
private int mBufSize;
private IDownloadListener mListener;
private DownloadStateConstance CONSTANCE;
private StateConstance CONSTANCE;
private long mSleepTime = 0;
SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener,
DownloadUtil.ChildThreadConfigEntity downloadInfo) {
SingleThreadTask(StateConstance constance, IDownloadListener listener,
ChildThreadConfigEntity downloadInfo) {
AriaManager manager = AriaManager.getInstance(AriaManager.APP);
CONSTANCE = constance;
CONSTANCE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut();

@ -13,13 +13,13 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arialyy.aria.core.download;
package com.arialyy.aria.core.download.downloader;
/**
* Created by lyy on 2017/1/18.
* 下载状态常量
*/
final class DownloadStateConstance {
final class StateConstance {
int CANCEL_NUM = 0;
int STOP_NUM = 0;
int FAIL_NUM = 0;
@ -32,7 +32,7 @@ final class DownloadStateConstance {
boolean isCancel = false;
boolean isStop = false;
DownloadStateConstance() {
StateConstance() {
}
void cleanState() {

@ -21,7 +21,7 @@ import com.arialyy.aria.orm.DbEntity;
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 {
/**
@ -36,6 +36,7 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
* 下载失败计数每次开始都重置为0
*/
@Ignore private int failNum = 0;
/**
* 扩展字段
*/
@ -53,10 +54,14 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
* 完成时间
*/
private long completeTime;
/**
* 文件名
*/
private String fileName = "";
public int getFailNum() {
return failNum;
}
public void setFailNum(int failNum) {
this.failNum = failNum;
}
public long getSpeed() {
return speed;
@ -74,14 +79,6 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
this.convertSpeed = convertSpeed;
}
public int getFailNum() {
return failNum;
}
public void setFailNum(int failNum) {
this.failNum = failNum;
}
public String getStr() {
return str;
}
@ -122,14 +119,6 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
this.completeTime = completeTime;
}
public String getFileName() {
return fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public AbsEntity() {
}
@ -146,7 +135,6 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
dest.writeInt(this.state);
dest.writeLong(this.currentProgress);
dest.writeLong(this.completeTime);
dest.writeString(this.fileName);
}
protected AbsEntity(Parcel in) {
@ -158,6 +146,5 @@ public abstract class AbsEntity extends DbEntity implements IEntity, Parcelable
this.state = in.readInt();
this.currentProgress = in.readLong();
this.completeTime = in.readLong();
this.fileName = in.readString();
}
}

@ -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.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 {
/**
* 组名
*/
@Primary
private String groupName = "";
/**
* 任务地址相加的urlmd5
*/
private String urlmd5 = "";
public String getUrlmd5() {
return urlmd5;
}
public void setUrlmd5(String urlmd5) {
this.urlmd5 = urlmd5;
}
public String getGroupName() {
return groupName;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
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.urlmd5);
}
protected AbsGroupEntity(Parcel in) {
super(in);
this.groupName = in.readString();
this.urlmd5 = in.readString();
}
}

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

@ -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 AbsNormalEntity> implements IReceiver<ENTITY>{
public String targetName;
public Object obj;
}

@ -16,150 +16,91 @@
package com.arialyy.aria.core.inf;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.RequestEnum;
import com.arialyy.aria.core.command.AbsCmd;
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.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.util.CommonUtil;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
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> {
protected ENTITY entity;
protected TASK_ENTITY taskEntity;
protected String targetName;
public abstract class AbsTarget<TARGET extends AbsTarget, ENTITY extends AbsEntity, TASK_ENTITY extends AbsTaskEntity>
implements ITarget<TARGET> {
protected ENTITY mEntity;
protected TASK_ENTITY mTaskEntity;
protected String mTargetName;
/**
* 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中
* 获取任务进度如果任务存在则返回当前进度
*
* @param str 扩展数据
*/
public AbsTarget setExtendField(String str) {
entity.setStr(str);
return this;
}
/**
* 获取存放的扩展字段
* 设置扩展字段{@link #setExtendField(String)}
* @return 该任务进度
*/
public String getExtendField() {
return entity.getStr();
public long getCurrentProgress() {
return mEntity == null ? -1 : mEntity.getCurrentProgress();
}
/**
* 获取任务状态
* 获取任务文件大小
*
* @return {@link IEntity}
*/
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) {
if (TextUtils.isEmpty(redirectUrlKey)) {
Log.w("AbsTarget", "重定向后,新url的key不能为null");
return;
}
taskEntity.redirectUrlKey = redirectUrlKey;
}
/**
* 删除记录
* @return 文件大小
*/
public void removeRecord() {
entity.deleteData();
@Override public long getSize() {
return mEntity == null ? 0 : mEntity.getFileSize();
}
/**
* 获取任务文件大小
* 获取单位转换后的文件大小
*
* @return 文件大小
* @return 文件大小{@code xxx mb}
*/
public long getFileSize() {
if (entity instanceof DownloadEntity) {
DownloadEntity entity = (DownloadEntity) this.entity;
return entity.getFileSize();
} else if (entity instanceof UploadEntity) {
UploadEntity entity = (UploadEntity) this.entity;
return entity.getFileSize();
}
return 0;
@Override public String getConvertSize() {
return mEntity == null ? "0b" : CommonUtil.formatFileSize(mEntity.getFileSize());
}
/**
* 获取单位转换后的文件大小
* 设置扩展字段用来保存你的其它数据如果你的数据比较多你可以把你的数据转换为JSON字符串然后再存到Aria中
*
* @return 文件大小{@code xxx mb}
* @param str 扩展数据
*/
public String getConvertFileSize() {
if (entity instanceof DownloadEntity) {
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";
public TARGET setExtendField(String str) {
mEntity.setStr(str);
return (TARGET) this;
}
/**
* 下载任务是否存在
* 获取存放的扩展字段
* 设置扩展字段{@link #setExtendField(String)}
*/
public boolean taskExists() {
return false;
public String getExtendField() {
return mEntity.getStr();
}
/**
* 获取任务进度百分比
* 获取任务状态
*
* @return 返回任务进度
* @return {@link IEntity}
*/
protected int getPercent() {
return 0;
public int getTaskState() {
return mEntity.getState();
}
/**
* 获取任务进度如果任务存在则返回当前进度
* 获取任务进度百分比
*
* @return 任务进度
* @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();
@Override public int getPercent() {
if (mEntity == null) {
Log.e("AbsTarget", "下载管理器中没有该任务");
return 0;
}
if (mEntity.getFileSize() != 0) {
return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize());
}
return -1;
return 0;
}
/**
@ -168,20 +109,22 @@ public abstract class AbsTarget<ENTITY extends AbsEntity, TASK_ENTITY extends Ab
* @param key 头部key
* @param header 头部value
*/
protected void _addHeader(@NonNull String key, @NonNull String header) {
taskEntity.headers.put(key, header);
public TARGET addHeader(@NonNull String key, @NonNull String header) {
mTaskEntity.headers.put(key, header);
return (TARGET) this;
}
/**
* 给url请求添加头部
*/
protected void _addHeaders(Map<String, String> headers) {
public TARGET addHeaders(Map<String, String> headers) {
if (headers != null && headers.size() > 0) {
Set<String> keys = headers.keySet();
for (String key : keys) {
taskEntity.headers.put(key, headers.get(key));
mTaskEntity.headers.put(key, headers.get(key));
}
}
return (TARGET) this;
}
/**
@ -189,62 +132,50 @@ public abstract class AbsTarget<ENTITY extends AbsEntity, TASK_ENTITY extends Ab
*
* @param requestEnum {@link RequestEnum}
*/
protected void _setRequestMode(RequestEnum requestEnum) {
taskEntity.requestEnum = requestEnum;
public TARGET setRequestMode(RequestEnum requestEnum) {
mTaskEntity.requestEnum = requestEnum;
return (TARGET) this;
}
/**
* 添加任务
* 开始下载
*/
public void add() {
@Override public void start() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CREATE))
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.exe();
}
/**
* 开始下载
* 停止下载
*
* @see #stop()
*/
public void start() {
List<AbsCmd> cmds = new ArrayList<>();
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();
@Deprecated public void pause() {
stop();
}
/**
* 停止下载
*/
protected void pause() {
@Override public void stop() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_STOP))
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_STOP))
.exe();
}
/**
* 恢复下载
*/
protected void resume() {
@Override public void resume() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_START))
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START))
.exe();
}
/**
* 取消下载
*/
public void cancel() {
@Override public void cancel() {
AriaManager.getInstance(AriaManager.APP)
.setCmd(CommonUtil.createCmd(targetName, taskEntity, CmdFactory.TASK_CANCEL))
.setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_CANCEL))
.exe();
}
/**
* 重新下载
*/
void reStart() {
cancel();
start();
}
}

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

@ -16,14 +16,22 @@
package com.arialyy.aria.core.inf;
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.Map;
/**
* 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 请求头
*/
@ -39,5 +47,20 @@ public abstract class AbsTaskEntity {
*/
public String redirectUrlKey = "location";
public abstract AbsEntity getEntity();
/**
* 用于判断删除任务时是否需要删除文件{@code true}删除
*/
@Ignore public boolean removeFile = false;
/**
* 是否支持断点, {@code true} 为支持断点
*/
public boolean isSupportBP = true;
/**
* 状态码
*/
public int code;
public abstract ENTITY getEntity();
}

@ -44,7 +44,7 @@ public interface IReceiver<ENTITY extends IEntity> {
/**
* 删除所有任务
*/
public void removeAllTask();
public void removeAllTask(boolean removeFile);
/**
* 任务是否存在

@ -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.
*/
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 为文件路径
@ -100,5 +92,4 @@ public interface ITask<ENTITY extends AbsEntity> {
public void setTargetName(String targetName);
public void removeRecord();
}

@ -18,27 +18,42 @@ package com.arialyy.aria.core.queue;
import android.util.Log;
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.ITask;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.queue.pool.CachePool;
import com.arialyy.aria.core.queue.pool.ExecutePool;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.pool.BaseCachePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import java.util.Set;
/**
* 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> {
private final String TAG = "AbsTaskQueue";
CachePool<TASK> mCachePool = new CachePool<>();
ExecutePool<TASK> mExecutePool;
BaseCachePool<TASK> mCachePool = new BaseCachePool<>();
BaseExecutePool<TASK> mExecutePool;
@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);
}
}
/**
* 停止所有任务
*/
@ -58,17 +73,27 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
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;
}
/**
* 获取缓存池
*/
public CachePool getCachePool() {
public BaseCachePool getCachePool() {
return mCachePool;
}
@ -90,8 +115,31 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
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) {
@ -112,12 +160,22 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
@Override public void stopTask(TASK task) {
if (!task.isRunning()) Log.w(TAG, "停止任务失败,【任务已经停止】");
task.setHighestPriority(false);
if (mExecutePool.removeTask(task)) {
task.stop();
} else {
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) ? "成功" : "失败"));
}
}
@ -133,6 +191,10 @@ abstract class AbsTaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
}
}
@Override public TASK getTask(ENTITY entity) {
return getTask(getKey(entity));
}
@Override public void removeTask(TASK task) {
task.cancel();
}

@ -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.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.BaseExecutePool;
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() {
mExecutePool = new BaseExecutePool<>(true);
}
@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);
} 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,7 @@ 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.download.DownloadTaskEntity;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.queue.pool.ExecutePool;
import com.arialyy.aria.core.queue.pool.DownloadExecutePool;
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
import java.util.LinkedHashSet;
import java.util.Map;
@ -48,10 +47,21 @@ public class DownloadTaskQueue
}
private DownloadTaskQueue() {
mExecutePool = new ExecutePool<>(true);
mExecutePool = new DownloadExecutePool(true);
}
@Override public void setTaskHighestPriority(DownloadTask task) {
@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);
Map<String, DownloadTask> exeTasks = mExecutePool.getAllTask();
if (exeTasks != null && !exeTasks.isEmpty()) {
@ -103,57 +113,21 @@ public class DownloadTaskQueue
}
}
@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.setMaxNum(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) {
DownloadTask task = null;
if (!TextUtils.isEmpty(target)) {
task = (DownloadTask) TaskFactory.getInstance()
.createTask(target, entity, DownloadSchedulers.getInstance());
entity.key = entity.getEntity().getDownloadUrl();
mCachePool.putTask(task);
} else {
Log.e(TAG, "target name 为 null!!");
Log.e(TAG, "target name 为 null!!");
}
return task;
}
@Override public DownloadTask getTask(DownloadEntity entity) {
return getTask(entity.getDownloadUrl());
}
@Override public void removeTask(DownloadEntity entity) {
DownloadTask task = mExecutePool.getTask(entity.getDownloadUrl());
if (task != null) {
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
}
task = mCachePool.getTask(entity.getDownloadUrl());
if (task != null) {
Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
}
@Override public void stopTask(DownloadTask task) {
task.setHighestPriority(false);
super.stopTask(task);
}
}

@ -19,8 +19,10 @@ package com.arialyy.aria.core.queue;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.download.DownloadTaskEntity;
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.ITask;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTask;
@ -30,7 +32,7 @@ import com.arialyy.aria.core.upload.UploadTaskEntity;
* 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判断任务是否正在执行
@ -46,11 +48,9 @@ public interface ITaskQueue<TASK extends ITask, TASK_ENTITY extends AbsTaskEntit
void stopAllTask();
/**
* 设置任务为最高优先级任务
*
* @param task {@link DownloadTask}{@link UploadTask}
* 删除所有任务
*/
void setTaskHighestPriority(TASK task);
void removeAllTask();
/**
* 开始任务

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

@ -19,7 +19,7 @@ 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.queue.pool.ExecutePool;
import com.arialyy.aria.core.queue.pool.BaseExecutePool;
import com.arialyy.aria.core.scheduler.UploadSchedulers;
import com.arialyy.aria.core.upload.UploadEntity;
import com.arialyy.aria.core.upload.UploadTask;
@ -43,11 +43,15 @@ public class UploadTaskQueue extends AbsTaskQueue<UploadTask, UploadTaskEntity,
}
private UploadTaskQueue() {
mExecutePool = new ExecutePool<>(false);
mExecutePool = new BaseExecutePool<>(false);
}
@Override public void setMaxTaskNum(int newMaxNum) {
@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) {
@ -55,25 +59,11 @@ public class UploadTaskQueue extends AbsTaskQueue<UploadTask, UploadTaskEntity,
if (!TextUtils.isEmpty(targetName)) {
task = (UploadTask) TaskFactory.getInstance()
.createTask(targetName, entity, UploadSchedulers.getInstance());
entity.key = entity.getEntity().getFilePath();
mCachePool.putTask(task);
} else {
Log.e(TAG, "target name 为 null是!!");
}
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) ? "成功" : "失败"));
}
}
}

@ -32,14 +32,14 @@ import java.util.concurrent.TimeUnit;
* Created by lyy on 2016/8/14.
* 任务缓存池所有下载任务最先缓存在这个池中
*/
public class CachePool<TASK extends ITask> implements IPool<TASK> {
private static final String TAG = "CachePool";
public class BaseCachePool<TASK extends ITask> implements IPool<TASK> {
private static final String TAG = "BaseCachePool";
private static final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数
private static final long TIME_OUT = 1000;
private Map<String, TASK> mCacheMap;
private LinkedBlockingQueue<TASK> mCacheQueue;
public CachePool() {
public BaseCachePool() {
mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM);
mCacheMap = new HashMap<>();
}
@ -95,7 +95,7 @@ public class CachePool<TASK extends ITask> implements IPool<TASK> {
@Override public TASK pollTask() {
synchronized (AriaManager.LOCK) {
try {
TASK task = null;
TASK task;
task = mCacheQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (task != null) {
String url = task.getKey();

@ -23,7 +23,6 @@ import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.util.CommonUtil;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;
@ -31,14 +30,14 @@ import java.util.concurrent.TimeUnit;
* Created by lyy on 2016/8/15.
* 任务执行池所有当前下载任务都该任务池中默认下载大小为2
*/
public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
private static final String TAG = "ExecutePool";
private static final long TIME_OUT = 1000;
private ArrayBlockingQueue<TASK> mExecuteQueue;
private Map<String, TASK> mExecuteMap;
private int mSize;
public class BaseExecutePool<TASK extends ITask> implements IPool<TASK> {
private final String TAG = "BaseExecutePool";
final long TIME_OUT = 1000;
ArrayBlockingQueue<TASK> mExecuteQueue;
Map<String, TASK> mExecuteMap;
protected int mSize;
public ExecutePool(boolean isDownload) {
public BaseExecutePool(boolean isDownload) {
if (isDownload) {
mSize = AriaManager.getInstance(AriaManager.APP).getDownloadConfig().getMaxTaskNum();
} else {
@ -67,10 +66,6 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
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);
}
@ -106,7 +101,7 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
*
* @param newTask 新任务
*/
private boolean putNewTask(TASK newTask) {
boolean putNewTask(TASK newTask) {
String url = newTask.getKey();
boolean s = mExecuteQueue.offer(newTask);
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
@ -119,16 +114,13 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
/**
* 队列满时将移除下载队列中的第一个任务
*/
private boolean pollFirstTask() {
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);
@ -142,7 +134,7 @@ public class ExecutePool<TASK extends ITask> implements IPool<TASK> {
@Override public TASK pollTask() {
synchronized (AriaManager.LOCK) {
try {
TASK task = null;
TASK task;
task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
if (task != null) {
String url = task.getKey();

@ -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.download.DownloadTask;
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 extends BaseExecutePool<DownloadTask> {
private final String TAG = "DownloadExecutePool";
public DownloadExecutePool(boolean isDownload) {
super(isDownload);
}
@Override public boolean putTask(DownloadTask 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 {
DownloadTask 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;
}
}

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

@ -21,9 +21,9 @@ import android.util.Log;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.download.DownloadTask;
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.IEntity;
import com.arialyy.aria.core.inf.ITask;
import com.arialyy.aria.core.queue.ITaskQueue;
import com.arialyy.aria.core.upload.UploadTask;
import java.util.Iterator;
@ -34,19 +34,19 @@ import java.util.concurrent.ConcurrentHashMap;
/**
* 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> {
private static final String TAG = "AbsSchedulers";
private final String TAG = "AbsSchedulers";
/**
* 下载的动态生成的代理类后缀
*/
String DOWNLOAD_PROXY_CLASS_SUFFIX = "$$DownloadListenerProxy";
private String DOWNLOAD_PROXY_CLASS_SUFFIX = "$$DownloadListenerProxy";
/**
* 上传的动态生成的代理类后缀
*/
String UPLOAD_PROXY_CLASS_SUFFIX = "$$UploadListenerProxy";
private String UPLOAD_PROXY_CLASS_SUFFIX = "$$UploadListenerProxy";
protected QUEUE mQueue;
protected boolean isDownload = true;
@ -131,7 +131,7 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
Log.e(TAG, "请传入下载任务");
return true;
}
callback(msg.what, task);
//callback(msg.what, task);
ENTITY entity = task.getEntity();
switch (msg.what) {
case STOP:
@ -154,6 +154,7 @@ public abstract class AbsSchedulers<TASK_ENTITY extends AbsTaskEntity, ENTITY ex
handleFailTask(task);
break;
}
callback(msg.what, task);
return true;
}

@ -0,0 +1,45 @@
/*
* 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();
isDownload = true;
}
public static DownloadGroupSchedulers getInstance() {
if (INSTANCE == null) {
synchronized (AriaManager.LOCK) {
INSTANCE = new DownloadGroupSchedulers();
}
}
return INSTANCE;
}
}

@ -29,7 +29,7 @@ import com.arialyy.aria.core.download.DownloadTask;
public class DownloadSchedulers
extends AbsSchedulers<DownloadTaskEntity, DownloadEntity, DownloadTask, DownloadTaskQueue> {
private static final String TAG = "DownloadSchedulers";
private final String TAG = "DownloadSchedulers";
private static volatile DownloadSchedulers INSTANCE = null;
private DownloadSchedulers() {

@ -17,15 +17,16 @@ package com.arialyy.aria.core.upload;
import android.os.Parcel;
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.Primary;
/**
* 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 boolean isComplete = false;

@ -17,12 +17,12 @@ package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.command.AbsCmd;
import com.arialyy.aria.core.command.CmdFactory;
import com.arialyy.aria.core.download.DownloadReceiver;
import com.arialyy.aria.core.command.normal.AbsNormalCmd;
import com.arialyy.aria.core.command.normal.NormalCmdFactory;
import com.arialyy.aria.core.download.DownloadTaskEntity;
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.scheduler.DownloadSchedulers;
import com.arialyy.aria.core.scheduler.ISchedulerListener;
import com.arialyy.aria.core.scheduler.UploadSchedulers;
import com.arialyy.aria.orm.DbEntity;
@ -37,10 +37,8 @@ import java.util.regex.Pattern;
* 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";
public String targetName;
public Object obj;
public ISchedulerListener<UploadTask> listener;
/**
@ -84,25 +82,30 @@ public class UploadReceiver implements IReceiver<UploadEntity> {
@Override public void stopAllTask() {
List<UploadEntity> allEntity = DbEntity.findAllData(UploadEntity.class);
List<AbsCmd> stopCmds = new ArrayList<>();
List<AbsNormalCmd> stopCmds = new ArrayList<>();
for (UploadEntity entity : allEntity) {
if (entity.getState() == IEntity.STATE_RUNNING) {
stopCmds.add(
CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), CmdFactory.TASK_STOP));
CommonUtil.createCmd(targetName, new UploadTaskEntity(), NormalCmdFactory.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);
List<UploadEntity> allEntity = DbEntity.findAllData(UploadEntity.class);
List<AbsCmd> cancelCmds = new ArrayList<>();
for (UploadEntity entity : allEntity) {
cancelCmds.add(
CommonUtil.createCmd(targetName, new UploadTaskEntity(entity), CmdFactory.TASK_CANCEL));
}
am.setCmds(cancelCmds).exe();
AriaManager.getInstance(AriaManager.APP)
.setCmd(
CommonUtil.createCmd(targetName, new DownloadTaskEntity(), NormalCmdFactory.TASK_CANCEL_ALL))
.exe();
Set<String> keys = am.getReceiver().keySet();
for (String key : keys) {
IReceiver receiver = am.getReceiver().get(key);
@ -118,8 +121,10 @@ public class UploadReceiver implements IReceiver<UploadEntity> {
/**
* 添加调度器回调
*
* @see #register()
*/
public UploadReceiver addSchedulerListener(ISchedulerListener<UploadTask> listener) {
@Deprecated public UploadReceiver addSchedulerListener(ISchedulerListener<UploadTask> listener) {
this.listener = listener;
UploadSchedulers.getInstance().addSchedulerListener(targetName, listener);
return this;

@ -16,27 +16,26 @@
package com.arialyy.aria.core.upload;
import android.support.annotation.NonNull;
import com.arialyy.aria.core.RequestEnum;
import com.arialyy.aria.core.inf.AbsTarget;
import com.arialyy.aria.core.inf.AbsNormalTarget;
import com.arialyy.aria.core.queue.UploadTaskQueue;
import java.util.Map;
/**
* 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) {
this.entity = entity;
this.targetName = targetName;
taskEntity = new UploadTaskEntity(entity);
this.mEntity = entity;
this.mTargetName = targetName;
mTaskEntity = new UploadTaskEntity();
mTaskEntity.entity = entity;
}
/**
* 设置userAgent
*/
public UploadTarget setUserAngent(@NonNull String userAgent) {
taskEntity.userAgent = userAgent;
mTaskEntity.userAgent = userAgent;
return this;
}
@ -46,7 +45,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* @param uploadUrl 上传路径
*/
public UploadTarget setUploadUrl(@NonNull String uploadUrl) {
taskEntity.uploadUrl = uploadUrl;
mTaskEntity.uploadUrl = uploadUrl;
return this;
}
@ -56,7 +55,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* @param attachment 附件key
*/
public UploadTarget setAttachment(@NonNull String attachment) {
taskEntity.attachment = attachment;
mTaskEntity.attachment = attachment;
return this;
}
@ -64,7 +63,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* 设置文件名
*/
public UploadTarget setFileName(String fileName) {
entity.setFileName(fileName);
mEntity.setFileName(fileName);
return this;
}
@ -74,28 +73,7 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* @param contentType tipmultipart/form-data
*/
public UploadTarget setContentType(String contentType) {
taskEntity.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);
mTaskEntity.contentType = contentType;
return this;
}
@ -103,28 +81,15 @@ public class UploadTarget extends AbsTarget<UploadEntity, UploadTaskEntity> {
* 下载任务是否存在
*/
@Override public boolean taskExists() {
return UploadTaskQueue.getInstance().getTask(entity.getFilePath()) != null;
}
/**
* 设置请求类型
*
* @param requestEnum {@link RequestEnum}
*/
public UploadTarget setRequestMode(RequestEnum requestEnum) {
super._setRequestMode(requestEnum);
return this;
}
private UploadEntity getUploadEntity() {
return entity;
return UploadTaskQueue.getInstance().getTask(mEntity.getFilePath()) != null;
}
/**
* 是否在下载
*/
public boolean isUploading() {
UploadTask task = UploadTaskQueue.getInstance().getTask(entity);
UploadTask task = UploadTaskQueue.getInstance().getTask(mEntity);
return task != null && task.isRunning();
}
}

@ -51,7 +51,7 @@ final class UploadUtil implements Runnable {
UploadUtil(UploadTaskEntity taskEntity, IUploadListener listener) {
mTaskEntity = taskEntity;
CheckUtil.checkTaskEntity(taskEntity);
mUploadEntity = taskEntity.uploadEntity;
mUploadEntity = taskEntity.getEntity();
if (listener == null) {
throw new IllegalArgumentException("上传监听不能为空");
}
@ -162,11 +162,11 @@ final class UploadUtil implements Runnable {
writer.append("Content-Disposition: form-data; name=\"")
.append(attachment)
.append("\"; filename=\"")
.append(mTaskEntity.uploadEntity.getFileName())
.append(mTaskEntity.getEntity().getFileName())
.append("\"")
.append(LINE_END);
writer.append("Content-Type: ")
.append(URLConnection.guessContentTypeFromName(mTaskEntity.uploadEntity.getFileName()))
.append(URLConnection.guessContentTypeFromName(mTaskEntity.getEntity().getFileName()))
.append(LINE_END);
writer.append("Content-Transfer-Encoding: binary").append(LINE_END);
writer.append(LINE_END);

@ -17,7 +17,11 @@ package com.arialyy.aria.orm;
import android.text.TextUtils;
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.UploadTaskEntity;
import java.util.HashMap;
import java.util.Map;
@ -28,7 +32,7 @@ import java.util.Map;
public class DBConfig {
static Map<String, Class> mapping = new HashMap<>();
static String DB_NAME;
static int VERSION = 3;
static int VERSION = 6;
static {
if (TextUtils.isEmpty(DB_NAME)) {
@ -41,6 +45,10 @@ public class DBConfig {
static {
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("UploadTaskEntity", UploadTaskEntity.class);
}
}

@ -19,8 +19,10 @@ package com.arialyy.aria.orm;
import android.support.annotation.NonNull;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Created by lyy on 2015/11/2.
@ -156,7 +158,7 @@ public class DbEntity {
private void updateRowID() {
try {
Field[] fields = CommonUtil.getFields(getClass());
List<Field> fields = CommonUtil.getAllFields(getClass());
List<String> where = new ArrayList<>();
List<String> values = new ArrayList<>();
for (Field field : fields) {
@ -165,7 +167,16 @@ public class DbEntity {
continue;
}
where.add(field.getName());
values.add(field.get(this) + "");
Type type = field.getType();
if (SqlHelper.isOneToOne(field)) {
values.add(SqlHelper.getOneToOneParams(field));
} else if (type == List.class) {
values.add(SqlHelper.getListElementParams(field));
} else if (type == Map.class) {
values.add(SqlHelper.map2Str((Map<String, String>) field.get(this)));
} else {
values.add(field.get(this) + "");
}
}
DbEntity entity = findData(getClass(), where.toArray(new String[where.size()]),
values.toArray(new String[values.size()]));

@ -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.
* 表ID字段指定
*/
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id {
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Primary {
int value() default -1;
}

@ -28,9 +28,13 @@ import com.arialyy.aria.util.CheckUtil;
import com.arialyy.aria.util.CommonUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
@ -186,12 +190,26 @@ final class SqlHelper extends SQLiteOpenHelper {
sql = String.format(sql, params);
print(FIND_DATA, sql);
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);
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);
}
/**
* 条件查寻数据
*/
@ -215,7 +233,7 @@ final class SqlHelper extends SQLiteOpenHelper {
}
print(FIND_DATA, sb.toString());
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);
return data;
@ -230,7 +248,7 @@ final class SqlHelper extends SQLiteOpenHelper {
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz));
print(FIND_ALL_DATA, sb.toString());
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);
return data;
@ -273,11 +291,22 @@ final class SqlHelper extends SQLiteOpenHelper {
}
sb.append(i > 0 ? ", " : "");
try {
Object value = field.get(dbEntity);
sb.append(field.getName())
.append("='")
.append(value == null ? "" : value.toString())
.append("'");
String value;
sb.append(field.getName()).append("='");
Type type = field.getType();
if (type == Map.class) {
value = map2Str((Map<String, String>) field.get(dbEntity));
} else if (type == List.class) {
value = getListElementParams(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) {
e.printStackTrace();
}
@ -307,24 +336,35 @@ final class SqlHelper extends SQLiteOpenHelper {
continue;
}
sb.append(i > 0 ? ", " : "");
//sb.append(getFieldName(field.getType(), field));
sb.append(field.getName());
i++;
}
sb.append(") VALUES (");
i = 0;
for (Field field : fields) {
field.setAccessible(true);
if (ignoreField(field)) {
continue;
}
sb.append(i > 0 ? ", " : "");
sb.append("'");
try {
sb.append(field.get(dbEntity)).append("'");
} catch (IllegalAccessException e) {
e.printStackTrace();
try {
for (Field field : fields) {
field.setAccessible(true);
if (ignoreField(field)) {
continue;
}
sb.append(i > 0 ? ", " : "");
sb.append("'");
Type type = field.getType();
if (type == Map.class) {
sb.append(map2Str((Map<String, String>) field.get(dbEntity)));
} else if (type == List.class) {
sb.append(getListElementParams(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(")");
print(INSERT_DATA, sb.toString());
@ -333,6 +373,47 @@ final class SqlHelper extends SQLiteOpenHelper {
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 getListElementParams(Field field) {
OneToMany oneToMany = field.getAnnotation(OneToMany.class);
if (oneToMany == null) {
throw new IllegalArgumentException("List中元素必须被@OneToMany注解");
}
//关联的表名
String tableName = oneToMany.table().getName();
//关联的字段
String key = oneToMany.key();
return tableName + "$$" + key;
}
/**
* 查找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;
}
/**
* 查找表是否存在
*
@ -383,9 +464,13 @@ final class SqlHelper extends SQLiteOpenHelper {
if (ignoreField(field)) {
continue;
}
sb.append(field.getName());
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");
} else if (type == int.class || type == Integer.class) {
sb.append(" interger");
@ -404,6 +489,9 @@ final class SqlHelper extends SQLiteOpenHelper {
} else {
continue;
}
if (isPrimary(field)) {
sb.append(" PRIMARY KEY");
}
sb.append(",");
}
String str = sb.toString();
@ -414,15 +502,32 @@ final class SqlHelper extends SQLiteOpenHelper {
close(db);
}
///**
// * 通过字段类型和获取保存在数据库表字段名
// */
//private static String getFieldName(Class<?> type, Field field) {
// String fieldName;
// if (type == Map.class) {
// fieldName = MAP_FIELD + field.getName();
// } else if (type == List.class) {
// fieldName = LIST_FIELD + field.getName();
// } else if (isGeneric(field)) {
// fieldName = GENERIC_FIELD + field.getName();
// } else {
// fieldName = field.getName();
// }
// return fieldName;
//}
/**
* 打印数据库日志
*
* @param type {@link DbUtil}
*/
static void print(int type, String sql) {
if (true) {
return;
}
//if (true) {
// return;
//}
String str = "";
switch (type) {
case CREATE_TABLE:
@ -450,8 +555,8 @@ final class SqlHelper extends SQLiteOpenHelper {
/**
* 根据数据游标创建一个具体的对象
*/
static synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz,
Cursor cursor) {
private static synchronized <T extends DbEntity> List<T> newInstanceEntity(SQLiteDatabase db,
Class<T> clazz, Cursor cursor) {
List<Field> fields = CommonUtil.getAllFields(clazz);
List<T> entitys = new ArrayList<>();
if (fields != null && fields.size() > 0) {
@ -482,8 +587,35 @@ final class SqlHelper extends SQLiteOpenHelper {
field.set(entity, new Date(cursor.getString(column)));
} else if (type == byte[].class) {
field.set(entity, cursor.getBlob(column));
} else {
continue;
} else if (type == Map.class) {
field.set(entity, str2Map(cursor.getString(column)));
} else if (type == List.class) {
//主键字段
String primaryKey = getPrimaryName(clazz);
if (TextUtils.isEmpty(primaryKey)) {
throw new IllegalArgumentException("List中的元素对象必须需要@Primary注解的字段");
}
//list字段保存的数据
int kc = cursor.getColumnIndex(primaryKey);
String params = cursor.getString(column);
String primaryData = cursor.getString(kc);
if (TextUtils.isEmpty(primaryData)) continue;
List<T> list = findForeignData(db, primaryData, params);
if (list == null) continue;
field.set(entity, findForeignData(db, primaryKey, params));
} 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() > 1) {
field.set(entity, list.get(0));
}
}
}
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
@ -499,6 +631,53 @@ final class SqlHelper extends SQLiteOpenHelper {
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) {
//if (db != null && db.isOpen()) db.close();
}
@ -523,4 +702,28 @@ final class SqlHelper extends SQLiteOpenHelper {
|| Modifier.isStatic(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.UploadTaskEntity;
import com.arialyy.aria.exception.FileException;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -76,6 +77,24 @@ public class CheckUtil {
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
*/
@ -88,9 +107,9 @@ public class CheckUtil {
*/
public static void checkTaskEntity(AbsTaskEntity entity) {
if (entity instanceof DownloadTaskEntity) {
checkDownloadTaskEntity(((DownloadTaskEntity) entity).downloadEntity);
checkDownloadTaskEntity(((DownloadTaskEntity) entity).getEntity());
} 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) {
boolean b = false;
if (entity instanceof DownloadTaskEntity) {
DownloadEntity entity1 = ((DownloadTaskEntity) entity).downloadEntity;
DownloadEntity entity1 = ((DownloadTaskEntity) entity).getEntity();
if (entity1 == null) {
Log.e(TAG, "下载实体不能为空");
} else if (checkType && TextUtils.isEmpty(entity1.getDownloadUrl())) {
@ -114,7 +133,7 @@ public class CheckUtil {
b = true;
}
} else if (entity instanceof UploadTaskEntity) {
UploadEntity entity1 = ((UploadTaskEntity) entity).uploadEntity;
UploadEntity entity1 = ((UploadTaskEntity) entity).getEntity();
if (entity1 == null) {
Log.e(TAG, "上传实体不能为空");
} else if (TextUtils.isEmpty(entity1.getFilePath())) {

@ -22,9 +22,12 @@ import android.content.SharedPreferences;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import com.arialyy.aria.core.command.CmdFactory;
import com.arialyy.aria.core.command.AbsCmd;
import com.arialyy.aria.core.AriaManager;
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.inf.AbsTaskEntity;
import com.arialyy.aria.core.upload.UploadEntity;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
@ -42,6 +45,11 @@ import java.util.Collections;
import java.util.List;
import java.util.Properties;
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.
@ -49,10 +57,123 @@ import java.util.regex.Pattern;
public class 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, UploadEntity entity) {
if (removeFile) {
File file = new File(entity.getFilePath());
if (file.exists()) {
file.delete();
}
}
File config = new File(
AriaManager.APP.getFilesDir().getPath() + "/temp/" + entity.getFileName() + ".properties");
if (config.exists()) {
config.delete();
}
entity.deleteData();
}
/**
* 删除下载任务的配置包括
*
* @param removeFile{@code true} 删除已经下载完成的任务不仅删除下载记录还会删除已经下载完成的文件{@code false}
* 如果文件已经下载完成只删除下载记录
*/
public static void delDownloadTaskConfig(boolean removeFile, DownloadEntity entity) {
if (removeFile) {
File file = new File(entity.getDownloadPath());
if (file.exists()) {
file.delete();
}
}
File config = new File(
AriaManager.APP.getFilesDir().getPath() + "/temp/" + entity.getFileName() + ".properties");
if (config.exists()) {
config.delete();
}
entity.deleteData();
}
/**
* 获取CPU核心数
*/
public static int getNumCores() {
public static int getCoresNum() {
//Private Class to display only CPU devices in the directory listing
class CpuFilter implements FileFilter {
@Override public boolean accept(File pathname) {
@ -180,8 +301,8 @@ public class CommonUtil {
}
}
public static <T extends AbsTaskEntity> AbsCmd createCmd(String target, T entity, int cmd) {
return CmdFactory.getInstance().createCmd(target, entity, cmd);
public static <T extends AbsTaskEntity> AbsNormalCmd createCmd(String target, T entity, int cmd) {
return NormalCmdFactory.getInstance().createCmd(target, entity, cmd);
}
/**

@ -11,4 +11,4 @@ dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
}
//apply from: 'bintray-release.gradle'
apply from: 'bintray-release.gradle'

@ -14,4 +14,4 @@ dependencies {
compile project(':AriaAnnotations')
}
//apply from: 'bintray-release.gradle'
apply from: 'bintray-release.gradle'

@ -42,7 +42,6 @@ dependencies {
compile 'com.squareup.okhttp3:okhttp:3.2.0'
compile 'com.arialyy.frame:MVVM2:2.2.0'
compile project(':Aria')
// compile 'com.arialyy.aria:aria-core:3.2.0'
// annotationProcessor 'com.arialyy.aria:aria-compiler:3.2.0'
compile project(':AriaCompiler')
}

@ -7,9 +7,6 @@
<!--设置下载线程,线程下载数改变后,新的下载任务才会生效,如果任务大小小于1m,该设置也不会生效-->
<threadNum value="4"/>
<!--是否打开下载广播,默认为false,不建议使用广播,你可以使用Download注解来实现事件回调-->
<openBroadcast value="false"/>
<!--设置下载队列最大任务数, 默认为2-->
<maxTaskNum value="2"/>
@ -40,8 +37,6 @@
</download>
<upload>
<!--是否打开上传广播,默认为false,不建议使用广播,你可以使用Upload注解来实现事件回调-->
<openBroadcast value="false"/>
<!--设置上传队列最大任务数, 默认为2-->
<maxTaskNum value="2"/>

@ -92,69 +92,4 @@ public class DownloadModule extends BaseModule {
return entity;
}
/**
* 下载广播过滤器
*/
public IntentFilter getDownloadFilter() {
IntentFilter filter = new IntentFilter();
filter.addDataScheme(getContext().getPackageName());
filter.addAction(Aria.ACTION_PRE);
filter.addAction(Aria.ACTION_POST_PRE);
filter.addAction(Aria.ACTION_RESUME);
filter.addAction(Aria.ACTION_START);
filter.addAction(Aria.ACTION_RUNNING);
filter.addAction(Aria.ACTION_STOP);
filter.addAction(Aria.ACTION_CANCEL);
filter.addAction(Aria.ACTION_COMPLETE);
filter.addAction(Aria.ACTION_FAIL);
return filter;
}
/**
* 创建Receiver
*/
public BroadcastReceiver createReceiver(final Handler handler) {
return new BroadcastReceiver() {
long len = 0;
@Override public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
switch (action) {
case Aria.ACTION_POST_PRE:
DownloadEntity entity = intent.getParcelableExtra(Aria.DOWNLOAD_ENTITY);
len = entity.getFileSize();
L.d(TAG, "download onPre");
handler.obtainMessage(SingleTaskActivity.DOWNLOAD_PRE, len).sendToTarget();
break;
case Aria.ACTION_START:
L.d(TAG, "download start");
break;
case Aria.ACTION_RESUME:
L.d(TAG, "download resume");
long location = intent.getLongExtra(Aria.CURRENT_LOCATION, 1);
handler.obtainMessage(SingleTaskActivity.DOWNLOAD_RESUME, location).sendToTarget();
break;
case Aria.ACTION_RUNNING:
long current = intent.getLongExtra(Aria.CURRENT_LOCATION, 0);
int progress = len == 0 ? 0 : (int) ((current * 100) / len);
handler.obtainMessage(SingleTaskActivity.DOWNLOAD_RUNNING, progress).sendToTarget();
break;
case Aria.ACTION_STOP:
L.d(TAG, "download stop");
handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_STOP);
break;
case Aria.ACTION_COMPLETE:
handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_COMPLETE);
break;
case Aria.ACTION_CANCEL:
handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_CANCEL);
break;
case Aria.ACTION_FAIL:
handler.sendEmptyMessage(SingleTaskActivity.DOWNLOAD_FAILE);
break;
}
}
};
}
}

@ -65,7 +65,7 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
"http://static.gaoshouyou.com/d/22/94/822260b849944492caadd2983f9bb624.apk";
//"http://down2.xiaoshuofuwuqi.com/d/file/filetxt/20170608/14/%BA%DA%CE%D7%CA%A6%E1%C8%C6%F0.txt";
//"http://tinghuaapp.oss-cn-shanghai.aliyuncs.com/20170612201739607815";
//"http://static.gaoshouyou.com/d/36/69/2d3699acfa69e9632262442c46516ad8.apk";
//"http://static.gaoshouyou.com/d/36/69/2d3699acfa69e9632262442c46516ad8.apk";
//"http://oqcpqqvuf.bkt.clouddn.com/ceshi.txt";
//"http://down8.androidgame-store.com/201706122321/97967927DD4E53D9905ECAA7874C8128/new/game1/19/45319/com.neuralprisma-2.5.2.174-2000174_1494784835.apk?f=web_1";
//不支持断点的链接
@ -209,6 +209,10 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
@Download.onTaskCancel(DOWNLOAD_URL) void taskCancel(DownloadTask task) {
mUpdateHandler.sendEmptyMessage(DOWNLOAD_CANCEL);
L.d(TAG, "task__cancel");
//Aria.download(this)
// .load(DOWNLOAD_URL)
// .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk")
// .add();
}
@Download.onTaskFail(DOWNLOAD_URL) void taskFail(DownloadTask task) {
@ -242,7 +246,6 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
setBtState(false);
}
mSize.setText(target.getConvertFileSize());
Aria.get(this).getDownloadConfig().setOpenBreadCast(true);
}
public void onClick(View view) {
@ -257,6 +260,11 @@ public class SingleTaskActivity extends BaseActivity<ActivitySingleBinding> {
} else if (text.equals("恢复")) {
Aria.download(this).load(DOWNLOAD_URL).resume();
}
//DownloadTarget target = Aria.download(this)
// .load(DOWNLOAD_URL)
// .setDownloadPath(Environment.getExternalStorageDirectory().getPath() + "/test.apk");
//target.add();
//target.cancel();
break;
case R.id.stop:
Aria.download(this).load(DOWNLOAD_URL).pause();

@ -106,10 +106,7 @@ public class MultiDownloadActivity extends BaseActivity<ActivityMultiDownloadBin
mAdapter.updateState(task.getDownloadEntity());
}
@Download.onTaskRunning({
"https://g37.gdl.netease.com/onmyoji_netease_10_1.0.20.apk",
"http://static.gaoshouyou.com/d/eb/f2/dfeba30541f209ab8a50d847fc1661ce.apk"
}) void taskRunning(DownloadTask task) {
@Download.onTaskRunning() void taskRunning(DownloadTask task) {
mAdapter.setProgress(task.getDownloadEntity());
}
}

@ -40,12 +40,8 @@ class Configuration {
/**
* 旧任务数
*/
public static int oldMaxTaskNum = 2;
public int oldMaxTaskNum = 2;
/**
* 是否发送任务广播true发送
*/
boolean isOpenBreadCast = false;
/**
* 任务队列最大任务数 默认为2
*/
@ -85,16 +81,6 @@ class Configuration {
return this;
}
public boolean isOpenBreadCast() {
return isOpenBreadCast;
}
public BaseConfig setOpenBreadCast(boolean openBreadCast) {
isOpenBreadCast = openBreadCast;
saveKey("isOpenBreadCast", openBreadCast + "");
return this;
}
public int getMaxTaskNum() {
return maxTaskNum;
}
@ -176,7 +162,8 @@ class Configuration {
try {
for (Field field : fields) {
int m = field.getModifiers();
if (Modifier.isFinal(m) || Modifier.isStatic(m)) {
if (field.getName().equals("oldMaxTaskNum") || Modifier.isFinal(m) || Modifier.isStatic(
m)) {
continue;
}
field.setAccessible(true);

@ -16,12 +16,10 @@
package com.arialyy.aria.core.upload;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.util.Log;
import com.arialyy.aria.core.Aria;
import com.arialyy.aria.core.AriaManager;
import com.arialyy.aria.core.inf.AbsTask;
import com.arialyy.aria.core.inf.AbsNormalTask;
import com.arialyy.aria.core.inf.IEntity;
import com.arialyy.aria.core.scheduler.ISchedulers;
import com.arialyy.aria.util.CommonUtil;
@ -31,16 +29,15 @@ import java.lang.ref.WeakReference;
* Created by lyy on 2017/2/23.
* 上传任务
*/
public class UploadTask extends AbsTask<UploadTaskEntity, UploadEntity> {
public class UploadTask extends AbsNormalTask<UploadEntity> {
private static final String TAG = "UploadTask";
private Handler mOutHandler;
private UploadUtil mUtil;
private UListener mListener;
private UploadTask(UploadTaskEntity taskEntity, Handler outHandler) {
mOutHandler = outHandler;
mEntity = taskEntity.uploadEntity;
mEntity = taskEntity.getEntity();
mListener = new UListener(mOutHandler, this);
mUtil = new UploadUtil(taskEntity, mListener);
}
@ -77,118 +74,99 @@ public class UploadTask extends AbsTask<UploadTaskEntity, UploadEntity> {
if (mOutHandler != null) {
mOutHandler.obtainMessage(ISchedulers.CANCEL, this).sendToTarget();
}
//发送取消下载的广播
Intent intent = CommonUtil.createIntent(AriaManager.APP.getPackageName(), Aria.ACTION_CANCEL);
intent.putExtra(Aria.UPLOAD_ENTITY, mEntity);
AriaManager.APP.sendBroadcast(intent);
}
}
private static class UListener extends UploadListener {
private static class
UListener extends UploadListener {
WeakReference<Handler> outHandler;
WeakReference<UploadTask> task;
long lastLen = 0; //上一次发送长度
long lastTime = 0;
long INTERVAL_TIME = 1000; //1m更新周期
boolean isFirst = true;
UploadEntity uploadEntity;
Intent sendIntent;
boolean isOpenBroadCast = false;
UploadEntity entity;
boolean isConvertSpeed = false;
Context context;
UListener(Handler outHandle, UploadTask task) {
this.outHandler = new WeakReference<>(outHandle);
this.task = new WeakReference<>(task);
uploadEntity = this.task.get().getEntity();
sendIntent = CommonUtil.createIntent(AriaManager.APP.getPackageName(), Aria.ACTION_RUNNING);
sendIntent.putExtra(Aria.UPLOAD_ENTITY, uploadEntity);
entity = this.task.get().getEntity();
context = AriaManager.APP;
final AriaManager manager = AriaManager.getInstance(context);
isOpenBroadCast = manager.getUploadConfig().isOpenBreadCast();
isConvertSpeed = manager.getUploadConfig().isConvertSpeed();
}
@Override public void onPre() {
uploadEntity.setState(IEntity.STATE_PRE);
sendIntent(Aria.ACTION_PRE, -1);
sendInState2Target(ISchedulers.PRE);
saveData(IEntity.STATE_PRE, -1);
}
@Override public void onPostPre(long fileSize) {
super.onPostPre(fileSize);
uploadEntity.setFileSize(fileSize);
uploadEntity.setState(IEntity.STATE_POST_PRE);
sendIntent(Aria.ACTION_POST_PRE, 0);
entity.setFileSize(fileSize);
sendInState2Target(ISchedulers.POST_PRE);
saveData(IEntity.STATE_POST_PRE, 0);
}
@Override public void onStart() {
uploadEntity.setState(IEntity.STATE_RUNNING);
sendIntent(Aria.ACTION_START, 0);
sendInState2Target(ISchedulers.START);
saveData(IEntity.STATE_RUNNING, 0);
}
@Override public void onResume(long resumeLocation) {
uploadEntity.setState(IEntity.STATE_RUNNING);
sendInState2Target(ISchedulers.RESUME);
sendIntent(Aria.ACTION_RESUME, resumeLocation);
saveData(IEntity.STATE_RUNNING, resumeLocation);
}
@Override public void onStop(long stopLocation) {
uploadEntity.setState(IEntity.STATE_STOP);
handleSpeed(0);
sendInState2Target(ISchedulers.STOP);
sendIntent(Aria.ACTION_STOP, stopLocation);
saveData(IEntity.STATE_STOP, stopLocation);
}
@Override public void onProgress(long 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);
uploadEntity.setCurrentProgress(currentLocation);
entity.setCurrentProgress(currentLocation);
lastLen = currentLocation;
sendInState2Target(ISchedulers.RUNNING);
AriaManager.APP.sendBroadcast(sendIntent);
}
}
@Override public void onCancel() {
uploadEntity.setState(IEntity.STATE_CANCEL);
handleSpeed(0);
sendInState2Target(ISchedulers.CANCEL);
sendIntent(Aria.ACTION_CANCEL, -1);
uploadEntity.deleteData();
saveData(IEntity.STATE_CANCEL, -1);
entity.deleteData();
}
@Override public void onComplete() {
uploadEntity.setState(IEntity.STATE_COMPLETE);
uploadEntity.setComplete(true);
entity.setComplete(true);
handleSpeed(0);
sendInState2Target(ISchedulers.COMPLETE);
sendIntent(Aria.ACTION_COMPLETE, uploadEntity.getFileSize());
saveData(IEntity.STATE_COMPLETE, entity.getFileSize());
}
@Override public void onFail() {
uploadEntity.setFailNum(uploadEntity.getFailNum() + 1);
uploadEntity.setState(IEntity.STATE_FAIL);
entity.setFailNum(entity.getFailNum() + 1);
handleSpeed(0);
sendInState2Target(ISchedulers.FAIL);
sendIntent(Aria.ACTION_FAIL, -1);
saveData(IEntity.STATE_FAIL, -1);
}
private void handleSpeed(long speed) {
if (isConvertSpeed) {
uploadEntity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
entity.setConvertSpeed(CommonUtil.formatFileSize(speed) + "/s");
} else {
uploadEntity.setSpeed(speed);
entity.setSpeed(speed);
}
}
@ -203,17 +181,11 @@ public class UploadTask extends AbsTask<UploadTaskEntity, UploadEntity> {
}
}
private void sendIntent(String action, long location) {
uploadEntity.setComplete(action.equals(Aria.ACTION_COMPLETE));
uploadEntity.setCurrentProgress(location);
uploadEntity.update();
if (!isOpenBroadCast) return;
Intent intent = CommonUtil.createIntent(context.getPackageName(), action);
intent.putExtra(Aria.UPLOAD_ENTITY, uploadEntity);
if (location != -1) {
intent.putExtra(Aria.CURRENT_LOCATION, location);
}
context.sendBroadcast(intent);
private void saveData(int state, long location) {
entity.setState(state);
entity.setComplete(state == IEntity.STATE_COMPLETE);
entity.setCurrentProgress(location);
entity.update();
}
}

@ -15,7 +15,9 @@
*/
package com.arialyy.aria.core.upload;
import com.arialyy.aria.core.download.DownloadEntity;
import com.arialyy.aria.core.inf.AbsTaskEntity;
import com.arialyy.aria.orm.OneToOne;
import java.util.HashMap;
import java.util.Map;
@ -23,24 +25,23 @@ import java.util.Map;
* Created by lyy on 2017/2/9.
* 上传任务实体
*/
public class UploadTaskEntity extends AbsTaskEntity {
public UploadEntity uploadEntity;
public class UploadTaskEntity extends AbsTaskEntity<UploadEntity> {
public String uploadUrl; //上传路径
public String attachment; //文件上传需要的key
public String contentType = "multipart/form-data"; //上传的文件类型
public String userAgent = "User-Agent";
public String charset = "utf-8";
@OneToOne(table = UploadEntity.class, key = "filePath") public UploadEntity entity;
/**
* 文件上传表单
*/
public Map<String, String> formFields = new HashMap<>();
public UploadTaskEntity(UploadEntity downloadEntity) {
this.uploadEntity = downloadEntity;
public UploadTaskEntity() {
}
@Override public UploadEntity getEntity() {
return uploadEntity;
return entity;
}
}

@ -7,7 +7,7 @@ buildscript {
dependencies {
// classpath 'com.android.tools.build:gradle:2.3.0'
classpath 'com.android.tools.build:gradle:2.2.2'
// classpath 'com.novoda:bintray-release:0.5.0'
classpath 'com.novoda:bintray-release:0.5.0'
// classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.7'
// classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
// NOTE: Do not place your application dependencies here; they belong
@ -37,8 +37,8 @@ task clean(type: Delete) {
ext {
userOrg = 'arialyy'
groupId = 'com.arialyy.aria'
// publishVersion = '0.0.6'
publishVersion = '3.1.9'
// publishVersion = '0.0.8'
publishVersion = '3.2.0'
repoName='maven'
desc = 'android 下载框架'
website = 'https://github.com/AriaLyy/Aria'

Loading…
Cancel
Save