diff --git a/Aria/build.gradle b/Aria/build.gradle index 9f7b3b26..41a68320 100644 --- a/Aria/build.gradle +++ b/Aria/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' diff --git a/Aria/src/main/java/com/arialyy/aria/core/Aria.java b/Aria/src/main/java/com/arialyy/aria/core/Aria.java index 27e19d2e..5dc70cfe 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/Aria.java +++ b/Aria/src/main/java/com/arialyy/aria/core/Aria.java @@ -59,62 +59,6 @@ import com.arialyy.aria.core.upload.UploadTask; * */ @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() { } diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index 5bcad9cb..41bb1525 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -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; diff --git a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java index 260d1d29..d0df8509 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/core/ConfigHelper.java @@ -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)) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java b/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java index 70d02300..db9e7b6c 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java +++ b/Aria/src/main/java/com/arialyy/aria/core/QueueMod.java @@ -6,8 +6,10 @@ package com.arialyy.aria.core; */ public enum QueueMod { /** - * 等待模式,如果执行队列已经满了,再次使用start命令执行任务时,该任务会被添加到缓存队列中 - * 当执行队列的任务完成时,将自动执行缓存队列中的任务 + * 等待模式, + * 如果执行队列已经满了,再对其它任务(TASK_A)使用start命令执行任务时 + * 1、TASK_A添加到缓存队列中,当执行队列中的任务完成时,系统会将自动执行缓存队列中的TASK_A + * 2、如果再次对TASK_A使用start命令,TASK_A将会立刻执行 */ WAIT("wait"), diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java index 8dc620c8..d337a453 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmd.java @@ -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 implements ICmd { - ITaskQueue mQueue; - T mTaskEntity; - String TAG; - String mTargetName; - /** - * 能否执行命令 - */ - boolean canExeCmd = true; +public abstract class AbsCmd 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; - } - } -} \ No newline at end of file + protected boolean isDownloadCmd = true; +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java new file mode 100644 index 00000000..9f447b49 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/AbsCmdFactory.java @@ -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 { + + /** + * @param target 创建任务的对象 + * @param entity 下载实体 + */ + public abstract CMD createCmd(String target, T entity, int type); +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ICmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java similarity index 90% rename from Aria/src/main/java/com/arialyy/aria/core/inf/ICmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java index 482cfb0c..dc938037 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/ICmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/ICmd.java @@ -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(); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java new file mode 100644 index 00000000..56b8e17d --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/AbsGroupCmd.java @@ -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 extends AbsCmd { + + /** + * @param targetName 创建任务的对象名 + */ + AbsGroupCmd(String targetName, T entity) { + mTargetName = targetName; + mTaskEntity = entity; + TAG = CommonUtil.getClassName(this); + if (entity instanceof DownloadGroupTaskEntity) { + mQueue = DownloadGroupTaskQueue.getInstance(); + isDownloadCmd = true; + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java new file mode 100644 index 00000000..5b6e5cf9 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCancelCmd.java @@ -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 extends AbsGroupCmd { + /** + * @param targetName 创建任务的对象名 + */ + GroupCancelCmd(String targetName, T entity) { + super(targetName, entity); + } + + @Override public void executeCmd() { + + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java new file mode 100644 index 00000000..786dd6b8 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupCmdFactory.java @@ -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 { + /** + * 启动任务 + */ + 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 AbsGroupCmd 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; + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java new file mode 100644 index 00000000..3bd7bea8 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStartCmd.java @@ -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 extends AbsGroupCmd { + /** + * @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); + } + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java new file mode 100644 index 00000000..85c400bd --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/group/GroupStopCmd.java @@ -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 extends AbsGroupCmd{ + /** + * @param targetName 创建任务的对象名 + */ + GroupStopCmd(String targetName, T entity) { + super(targetName, entity); + } + + @Override public void executeCmd() { + + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java new file mode 100644 index 00000000..e690524d --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AbsNormalCmd.java @@ -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 extends AbsCmd { + + /** + * 能否执行命令 + */ + 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; + } + } +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java similarity index 82% rename from Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java index 4177dc1d..8ed5de0d 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/AddCmd.java @@ -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 extends AbsCmd { +class AddCmd extends AbsNormalCmd { AddCmd(String targetName, T entity) { super(targetName, entity); @@ -33,7 +34,7 @@ class AddCmd extends AbsCmd { @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); diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java new file mode 100644 index 00000000..f68b3bcc --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelAllCmd.java @@ -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 extends AbsNormalCmd { + /** + * @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 allEntity = DbEntity.findAllData(UploadEntity.class); + for (UploadEntity entity : allEntity) { + CommonUtil.delUploadTaskConfig(mTaskEntity.removeFile, entity); + } + } + + /** + * 处理下载的删除 + */ + private void handleDownloadRemove() { + List allEntity = DbEntity.findAllData(DownloadEntity.class); + for (DownloadEntity entity : allEntity) { + CommonUtil.delDownloadTaskConfig(mTaskEntity.removeFile, entity); + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java similarity index 81% rename from Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java index fd51ad14..ff859066 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/CancelCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/CancelCmd.java @@ -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 extends AbsCmd { +class CancelCmd extends AbsNormalCmd { 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); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java similarity index 78% rename from Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java index 57dc35bb..e0efa2f7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/HighestPriorityCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/HighestPriorityCmd.java @@ -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 extends AbsCmd { +final class HighestPriorityCmd extends AbsNormalCmd { /** * @param targetName 产生任务的对象名 */ @@ -39,15 +43,15 @@ final class HighestPriorityCmd extends AbsCmd { @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); } } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java similarity index 80% rename from Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java index ae725b51..85aa33fc 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/NormalCmdFactory.java @@ -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 { /** * 创建任务 */ @@ -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 AbsCmd createCmd(String target, T entity, int type) { + public AbsNormalCmd 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; } diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java similarity index 76% rename from Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java index cb87dee7..2a019bb7 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/ResumeAllCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/ResumeAllCmd.java @@ -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 extends AbsCmd { +final class ResumeAllCmd extends AbsNormalCmd { /** * @param targetName 产生任务的对象名 */ @@ -29,7 +29,7 @@ final class ResumeAllCmd extends AbsCmd { 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 extends AbsCmd { } } - 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, "添加命令执行失败,【该任务已经存在】"); diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java similarity index 54% rename from Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java index a9a3d180..2b042a27 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/StartCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StartCmd.java @@ -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 extends AbsCmd { +class StartCmd extends AbsNormalCmd { StartCmd(String targetName, T entity) { super(targetName, entity); @@ -34,31 +36,38 @@ class StartCmd extends AbsCmd { @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); + } } } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StopAllCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java similarity index 75% rename from Aria/src/main/java/com/arialyy/aria/core/command/StopAllCmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java index 2c16378e..431adfdd 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/StopAllCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopAllCmd.java @@ -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 extends AbsCmd { +final class StopAllCmd extends AbsNormalCmd { /** * @param targetName 产生任务的对象名 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java similarity index 86% rename from Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java rename to Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java index 8712d6cc..9d0b0811 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/command/StopCmd.java +++ b/Aria/src/main/java/com/arialyy/aria/core/command/normal/StopCmd.java @@ -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 extends AbsCmd { +class StopCmd extends AbsNormalCmd { StopCmd(String targetName, T entity) { super(targetName, entity); @@ -34,7 +34,7 @@ class StopCmd extends AbsCmd { @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); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java index 5c0e18bf..340c91f1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java @@ -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(); } - @Ignore public static final Creator CREATOR = new Creator() { + @Override public String toString() { + return "DownloadEntity{" + + "downloadUrl='" + + downloadUrl + + '\'' + + ", downloadPath='" + + downloadPath + + '\'' + + ", isDownloadComplete=" + + isDownloadComplete + + ", isRedirect=" + + isRedirect + + ", redirectUrl='" + + redirectUrl + + '\'' + + ", groupName='" + + groupName + + '\'' + + '}'; + } + + public static final Creator CREATOR = new Creator() { @Override public DownloadEntity createFromParcel(Parcel source) { return new DownloadEntity(source); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java new file mode 100644 index 00000000..5b82ddfc --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupEntity.java @@ -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 mChild = new LinkedList<>(); + + public List getChild() { + return mChild; + } + + public void setChild(List 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 CREATOR = new Creator() { + @Override public DownloadGroupEntity createFromParcel(Parcel source) { + return new DownloadGroupEntity(source); + } + + @Override public DownloadGroupEntity[] newArray(int size) { + return new DownloadGroupEntity[size]; + } + }; +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java new file mode 100644 index 00000000..9a60b807 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupListener.java @@ -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 { + +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java new file mode 100644 index 00000000..9983edad --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTarget.java @@ -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 { + private List mUrls; + + DownloadGroupTarget(DownloadGroupEntity entity, String targetName, List urls) { + this.mEntity = entity; + this.mTargetName = targetName; + this.mUrls = urls; + mTaskEntity = new DownloadGroupTaskEntity(); + mTaskEntity.entity = entity; + } + + /** + * 设置保存路径组 + */ + public DownloadGroupTarget setDownloadPaths(List 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java new file mode 100644 index 00000000..9c3d778e --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTask.java @@ -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 { + 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 outHandler; + WeakReference 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; + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java new file mode 100644 index 00000000..4987a1d0 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadGroupTaskEntity.java @@ -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 { + + @OneToOne(table = DownloadGroupEntity.class, key = "groupName") public DownloadGroupEntity entity; + + @Override public DownloadGroupEntity getEntity() { + return entity; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java index 130b75c3..5b6589c6 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadReceiver.java @@ -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 { - private static final String TAG = "DownloadReceiver"; - public String targetName; - public Object obj; +public class DownloadReceiver extends AbsReceiver { + private final String TAG = "DownloadReceiver"; public ISchedulerListener listener; /** @@ -77,15 +74,17 @@ public class DownloadReceiver implements IReceiver { } /** - * 添加调度器回调 - * - * @see #register() + * 加载下载地址,如果任务组的中的下载地址改变了,则任务从新的一个任务组 */ - @Deprecated public DownloadReceiver addSchedulerListener( - ISchedulerListener listener) { - this.listener = listener; - DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener); - return this; + public DownloadGroupTarget load(List 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 { DownloadSchedulers.getInstance().unRegister(obj); } + /** + * 添加调度器回调 + * + * @see #register() + */ + @Deprecated public DownloadReceiver addSchedulerListener( + ISchedulerListener listener) { + this.listener = listener; + DownloadSchedulers.getInstance().addSchedulerListener(targetName, listener); + return this; + } + /** * 移除回调 * @@ -142,9 +153,10 @@ public class DownloadReceiver implements IReceiver { * 停止所有正在下载的任务,并清空等待队列。 */ @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 { * 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 allEntity = DbEntity.findAllData(DownloadEntity.class); - List 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 keys = ariaManager.getReceiver().keySet(); for (String key : keys) { IReceiver receiver = ariaManager.getReceiver().get(key); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java index 05e6c2d9..e6bab790 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTarget.java @@ -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 { +public class DownloadTarget extends + AbsNormalTarget { 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 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 { +public class DownloadTask extends AbsNormalTask { 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 { * 暂停任务,并让任务处于等待状态 */ @Override public void stopAndWait() { - super.stopAndWait(); stop(true); } @@ -142,11 +142,6 @@ public class DownloadTask extends AbsTask { 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 { 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 { 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 { WeakReference outHandler; WeakReference 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 { 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 { } } - 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(); } } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java index 75f6a17b..13d1c6fd 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadTaskEntity.java @@ -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 { - 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; } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java deleted file mode 100644 index d91271e4..00000000 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java +++ /dev/null @@ -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 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 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; - } -} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java new file mode 100644 index 00000000..94b865ea --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ChildThreadConfigEntity.java @@ -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; +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/ConnectionHelp.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java similarity index 97% rename from Aria/src/main/java/com/arialyy/aria/core/download/ConnectionHelp.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java index e05f0aee..028db87c 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/ConnectionHelp.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/ConnectionHelp.java @@ -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; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java new file mode 100644 index 00000000..7dbd2585 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadGroupUtil.java @@ -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 mExeMap = new HashMap<>(); + + /** + * 下载失败的映射表,key为下载地址 + */ + private Map mFailMap = new HashMap<>(); + + /** + * 下载器映射表,key为下载地址 + */ + private Map mDownloaderMap = new HashMap<>(); + + /** + * 文件信息回调组 + */ + private SparseArray 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 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 keys = mDownloaderMap.keySet(); + for (String key : keys) { + Downloader dt = mDownloaderMap.get(key); + if (dt != null) { + dt.stopDownload(); + } + } + } + + @Override public void startDownload() { + isRunning = true; + Set 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(); + } + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java similarity index 92% rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java index a2cbf237..f8d2349e 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadListener.java @@ -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) { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java new file mode 100644 index 00000000..1555dc67 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/DownloadUtil.java @@ -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(); + } +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java new file mode 100644 index 00000000..ad127c1b --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/Downloader.java @@ -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 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 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(); + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java new file mode 100644 index 00000000..d47a1d3b --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/FileInfoThread.java @@ -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); + } + } +} \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadListener.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java similarity index 95% rename from Aria/src/main/java/com/arialyy/aria/core/download/IDownloadListener.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java index 0e805e35..7b77cd59 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadListener.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadListener.java @@ -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 { /** * 支持断点回调 diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java similarity index 80% rename from Aria/src/main/java/com/arialyy/aria/core/download/IDownloadUtil.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java index 471d0048..bcfe8a5a 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/IDownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/IDownloadUtil.java @@ -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); } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java similarity index 97% rename from Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java index b46b8750..278f4873 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/SingleThreadTask.java @@ -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(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java similarity index 94% rename from Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java rename to Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java index 8c815ee9..fa082bd9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/downloader/StateConstance.java @@ -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() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java index e6b4d2b9..d69d1b43 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsEntity.java @@ -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(); } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java new file mode 100644 index 00000000..6a708b98 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupEntity.java @@ -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(); + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java new file mode 100644 index 00000000..c514577b --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTarget.java @@ -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 + extends AbsTarget { + +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java new file mode 100644 index 00000000..83bc8993 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsGroupTask.java @@ -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 + extends AbsTask { + + protected TASK_ENTITY mTaskEntity; + + + @Override public String getKey() { + return mEntity.getGroupName(); + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java new file mode 100644 index 00000000..d1425f7f --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalEntity.java @@ -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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java new file mode 100644 index 00000000..31de1c13 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTarget.java @@ -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 + extends AbsTarget { + + /** + * 将任务设置为最高优先级任务,最高优先级任务有以下特点: + * 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(); + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java new file mode 100644 index 00000000..c86dc3c2 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsNormalTask.java @@ -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 extends AbsTask { + + 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java new file mode 100644 index 00000000..e19d6945 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsReceiver.java @@ -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 implements IReceiver{ + public String targetName; + public Object obj; + +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java index 4a286ba5..1d96daba 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTarget.java @@ -16,36 +16,58 @@ 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 { - protected ENTITY entity; - protected TASK_ENTITY taskEntity; - protected String targetName; +public abstract class AbsTarget + implements ITarget { + protected ENTITY mEntity; + protected TASK_ENTITY mTaskEntity; + protected String mTargetName; + + /** + * 获取任务进度,如果任务存在,则返回当前进度 + * + * @return 该任务进度 + */ + public long getCurrentProgress() { + return mEntity == null ? -1 : mEntity.getCurrentProgress(); + } + + /** + * 获取任务文件大小 + * + * @return 文件大小 + */ + @Override public long getSize() { + return mEntity == null ? 0 : mEntity.getFileSize(); + } + + /** + * 获取单位转换后的文件大小 + * + * @return 文件大小{@code xxx mb} + */ + @Override public String getConvertSize() { + return mEntity == null ? "0b" : CommonUtil.formatFileSize(mEntity.getFileSize()); + } /** * 设置扩展字段,用来保存你的其它数据,如果你的数据比较多,你可以把你的数据转换为JSON字符串,然后再存到Aria中 * * @param str 扩展数据 */ - public AbsTarget setExtendField(String str) { - entity.setStr(str); - return this; + public TARGET setExtendField(String str) { + mEntity.setStr(str); + return (TARGET) this; } /** @@ -53,7 +75,7 @@ public abstract class AbsTarget headers) { + public TARGET addHeaders(Map headers) { if (headers != null && headers.size() > 0) { Set 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 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(); + @Override public void start() { + AriaManager.getInstance(AriaManager.APP) + .setCmd(CommonUtil.createCmd(mTargetName, mTaskEntity, NormalCmdFactory.TASK_START)) + .exe(); } /** * 停止下载 + * + * @see #stop() */ - protected void pause() { + @Deprecated public void pause() { + stop(); + } + + @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(); - } } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java index 64e6f543..2a235c7a 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/AbsTask.java @@ -16,25 +16,89 @@ 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 - implements ITask { +public abstract class AbsTask implements ITask { 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 如:已经下载3mb的大小,则返回{@code 3mb} + */ + @Override public String getConvertCurrentProgress() { + if (mEntity.getCurrentProgress() == 0) { + return "0b"; + } + return CommonUtil.formatFileSize(mEntity.getCurrentProgress()); + } + + /** + * 转换单位后的文件长度 + * + * @return 如果文件长度为0,则返回0m,否则返回转换后的长度1b、1kb、1mb、1gb、1tb + */ + @Override public String getConvertFileSize() { + if (mEntity.getFileSize() == 0) { + return "0mb"; + } + return CommonUtil.formatFileSize(mEntity.getFileSize()); + } + + /** + * 获取文件大小 + */ + @Override public long getFileSize() { + return mEntity.getFileSize(); + } + + /** + * 获取百分比进度 + * + * @return 返回百分比进度,如果文件长度为0,返回0 + */ + @Override public int getPercent() { + if (mEntity.getFileSize() == 0) { + return 0; + } + return (int) (mEntity.getCurrentProgress() * 100 / mEntity.getFileSize()); + } + + /** + * 任务当前状态 + * + * @return {@link IEntity} + */ + public int getState() { + return mEntity == null ? IEntity.STATE_OTHER : mEntity.getState(); + } + + /** + * 获取保存的扩展字段 + * + * @return 如果实体不存在,则返回null,否则返回扩展字段 + */ + @Override public String getExtendField() { + return mEntity == null ? null : mEntity.getStr(); } /** @@ -79,84 +143,10 @@ public abstract class AbsTask 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(); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java index 0c8d701c..19b1b11f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/IReceiver.java @@ -44,7 +44,7 @@ public interface IReceiver { /** * 删除所有任务 */ - public void removeAllTask(); + public void removeAllTask(boolean removeFile); /** * 任务是否存在 diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java new file mode 100644 index 00000000..6a12071b --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITarget.java @@ -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 { + /** + * 任务文件大小 + */ + 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 headers); + + /** + * 设置请求类型 + * + * @param requestEnum {@link RequestEnum} + */ + TARGET setRequestMode(RequestEnum requestEnum); + + /** + * 开始下载 + */ + void start(); + + /** + * 停止下载 + */ + void stop(); + + /** + * 恢复下载 + */ + void resume(); + + /** + * 取消下载 + */ + void cancel(); + +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java index 27b4af9b..70bee951 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/inf/ITask.java @@ -18,25 +18,17 @@ package com.arialyy.aria.core.inf; /** * Created by lyy on 2017/2/13. */ - public interface ITask { /** - * 暂停任务,并让任务处于等待状态 + * 获取下载状态 */ - 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 { public void setTargetName(String targetName); - public void removeRecord(); } diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java index faab3440..2edafc91 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/AbsTaskQueue.java @@ -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 +abstract class AbsTaskQueue implements ITaskQueue { private final String TAG = "AbsTaskQueue"; - CachePool mCachePool = new CachePool<>(); - ExecutePool mExecutePool; + BaseCachePool mCachePool = new BaseCachePool<>(); + BaseExecutePool mExecutePool; @Override public boolean taskIsRunning(String key) { return mExecutePool.getTask(key) != null; } + @Override public void removeAllTask() { + Set exeKeys = mExecutePool.getAllTask().keySet(); + for (String key : exeKeys) { + TASK task = mExecutePool.getAllTask().get(key); + if (task != null) task.cancel(); + } + Set cacheKeys = mCachePool.getAllTask().keySet(); + for (String key : cacheKeys) { + mExecutePool.removeTask(key); + } + } + /** * 停止所有任务 */ @@ -58,17 +73,27 @@ abstract class AbsTaskQueue= 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 { + 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java index 9a116ee9..7cf4d0ed 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/DownloadTaskQueue.java @@ -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 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); } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java index f6fd93d5..01453ae0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/ITaskQueue.java @@ -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 { +public interface ITaskQueue { /** * 通过key判断任务是否正在执行 @@ -46,11 +48,9 @@ public interface ITaskQueue {@link DownloadTaskEntity}、{@link UploadTaskEntity} - * @param {@link DownloadSchedulers} - * @return {@link DownloadTask}、{@link UploadTask} + * @param {@link DownloadTaskEntity}、{@link UploadTaskEntity}、{@link + * DownloadGroupTaskEntity} + * @param {@link DownloadSchedulers}、{@link UploadSchedulers} + * @return {@link DownloadTask}、{@link UploadTask}、{@link DownloadGroupTask} */ - ITask createTask(String targetName, - ENTITY entity, SCHEDULER schedulers) { + 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} diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java index 2b56ac84..b58013f9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/UploadTaskQueue.java @@ -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(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 implements IPool { - private static final String TAG = "CachePool"; +public class BaseCachePool implements IPool { + private static final String TAG = "BaseCachePool"; private static final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数 private static final long TIME_OUT = 1000; private Map mCacheMap; private LinkedBlockingQueue mCacheQueue; - public CachePool() { + public BaseCachePool() { mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM); mCacheMap = new HashMap<>(); } @@ -95,7 +95,7 @@ public class CachePool implements IPool { @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(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java similarity index 87% rename from Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java rename to Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java index 6892d208..edcb67a4 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/ExecutePool.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/BaseExecutePool.java @@ -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 implements IPool { - private static final String TAG = "ExecutePool"; - private static final long TIME_OUT = 1000; - private ArrayBlockingQueue mExecuteQueue; - private Map mExecuteMap; - private int mSize; +public class BaseExecutePool implements IPool { + private final String TAG = "BaseExecutePool"; + final long TIME_OUT = 1000; + ArrayBlockingQueue mExecuteQueue; + Map 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 implements IPool { return false; } else { if (mExecuteQueue.size() >= mSize) { - Set 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 implements IPool { * * @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 implements IPool { /** * 队列满时,将移除下载队列中的第一个任务 */ - 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 implements IPool { @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(); diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java new file mode 100644 index 00000000..0e8e53b0 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/DownloadExecutePool.java @@ -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 { + 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 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java index 970c22b9..7e143b9b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java +++ b/Aria/src/main/java/com/arialyy/aria/core/queue/pool/IPool.java @@ -22,18 +22,18 @@ import com.arialyy.aria.core.inf.ITask; * Created by lyy on 2016/8/14. * 任务池 */ -public interface IPool { +interface IPool { /** * 将下载任务添加到任务池中 */ - public boolean putTask(T task); + boolean putTask(T task); /** * 按照队列原则取出下载任务 * * @return 返回null或者下载任务 */ - public T pollTask(); + T pollTask(); /** * 通过下载链接获取下载任务,当任务不为空时,队列将删除该下载任务 @@ -41,7 +41,7 @@ public interface IPool { * @param downloadUrl 下载链接 * @return 返回null或者下载任务 */ - public T getTask(String downloadUrl); + T getTask(String downloadUrl); /** * 删除任务池中的下载任务 @@ -49,7 +49,7 @@ public interface IPool { * @param task 下载任务 * @return true:移除成功 */ - public boolean removeTask(T task); + boolean removeTask(T task); /** * 通过key除下载任务 @@ -57,12 +57,12 @@ public interface IPool { * @param key 下载链接 * @return true:移除成功 */ - public boolean removeTask(String key); + boolean removeTask(String key); /** * 池子大小 * * @return 返回缓存池或者执行池大小 */ - public int size(); + int size(); } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java b/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java index 4aa14f66..255662ab 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java +++ b/Aria/src/main/java/com/arialyy/aria/core/scheduler/AbsSchedulers.java @@ -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, QUEUE extends ITaskQueue> +abstract class AbsSchedulers, QUEUE extends ITaskQueue> implements ISchedulers { - 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 { + 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; + } +} diff --git a/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java b/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java index f6137abf..46e80fc0 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java +++ b/Aria/src/main/java/com/arialyy/aria/core/scheduler/DownloadSchedulers.java @@ -29,7 +29,7 @@ import com.arialyy.aria.core.download.DownloadTask; public class DownloadSchedulers extends AbsSchedulers { - private static final String TAG = "DownloadSchedulers"; + private final String TAG = "DownloadSchedulers"; private static volatile DownloadSchedulers INSTANCE = null; private DownloadSchedulers() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java index dafc69d9..39cc014f 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadEntity.java @@ -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; diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java index 38e71953..38ca3487 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadReceiver.java @@ -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 { +public class UploadReceiver extends AbsReceiver { private static final String TAG = "DownloadReceiver"; - public String targetName; - public Object obj; public ISchedulerListener listener; /** @@ -84,25 +82,30 @@ public class UploadReceiver implements IReceiver { @Override public void stopAllTask() { List allEntity = DbEntity.findAllData(UploadEntity.class); - List stopCmds = new ArrayList<>(); + List 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 allEntity = DbEntity.findAllData(UploadEntity.class); - List 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 keys = am.getReceiver().keySet(); for (String key : keys) { IReceiver receiver = am.getReceiver().get(key); @@ -118,8 +121,10 @@ public class UploadReceiver implements IReceiver { /** * 添加调度器回调 + * + * @see #register() */ - public UploadReceiver addSchedulerListener(ISchedulerListener listener) { + @Deprecated public UploadReceiver addSchedulerListener(ISchedulerListener listener) { this.listener = listener; UploadSchedulers.getInstance().addSchedulerListener(targetName, listener); return this; diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java index f991f7f9..5e97d0cb 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadTarget.java @@ -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 { +public class UploadTarget extends AbsNormalTarget { 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 { * @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 { * @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 { * 设置文件名 */ public UploadTarget setFileName(String fileName) { - entity.setFileName(fileName); + mEntity.setFileName(fileName); return this; } @@ -74,28 +73,7 @@ public class UploadTarget extends AbsTarget { * @param contentType tip:multipart/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头部的key,Value为http头对应的配置 - */ - public UploadTarget addHeaders(Map headers) { - super._addHeaders(headers); + mTaskEntity.contentType = contentType; return this; } @@ -103,28 +81,15 @@ public class UploadTarget extends AbsTarget { * 下载任务是否存在 */ @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(); } + } diff --git a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java index 88a87caa..008869ef 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/upload/UploadUtil.java @@ -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); diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java index faf40925..ec9f92eb 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java @@ -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 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); } } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java b/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java index fc42e75c..2e195018 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java @@ -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 fields = CommonUtil.getAllFields(getClass()); List where = new ArrayList<>(); List 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) 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()])); diff --git a/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java b/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java new file mode 100644 index 00000000..8f529e1b --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/OneToMany.java @@ -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 table(); + /** + * 关联的主键 + */ + String key(); +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java b/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java new file mode 100644 index 00000000..7641fd55 --- /dev/null +++ b/Aria/src/main/java/com/arialyy/aria/orm/OneToOne.java @@ -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 table(); + + /** + * 关联的主键 + */ + String key(); +} diff --git a/Aria/src/main/java/com/arialyy/aria/orm/Id.java b/Aria/src/main/java/com/arialyy/aria/orm/Primary.java similarity index 97% rename from Aria/src/main/java/com/arialyy/aria/orm/Id.java rename to Aria/src/main/java/com/arialyy/aria/orm/Primary.java index a59b85d9..365f1713 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/Id.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/Primary.java @@ -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; } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java index 4920bef0..4eeaa338 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java @@ -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 data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; + List data = cursor.getCount() > 0 ? newInstanceEntity(db, clazz, cursor) : null; cursor.close(); close(db); return data; } + /** + * 条件查寻数据 + */ + static synchronized List findData(SQLiteDatabase db, String tableName, + String... expression) { + Class clazz = null; + try { + clazz = (Class) 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 data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; + List 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 data = cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null; + List 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) 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; + 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) 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++; } - sb.append(i > 0 ? ", " : ""); - sb.append("'"); - try { - sb.append(field.get(dbEntity)).append("'"); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } - 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 clazz) { + List 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 List newInstanceEntity(Class clazz, - Cursor cursor) { + private static synchronized List newInstanceEntity(SQLiteDatabase db, + Class clazz, Cursor cursor) { List fields = CommonUtil.getAllFields(clazz); List 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 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 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 List findForeignData(SQLiteDatabase db, String primary, + String childParams) { + String[] params = childParams.split("\\$\\$"); + return findData(db, params[0], params[1] + "=?", primary); + } + + /** + * 字符串转Map,只支持 + *
+   *   {@code Map}
+   * 
+ */ + private static Map str2Map(String str) { + Map 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转字符串,只支持 + *
+   *   {@code Map}
+   * 
+ */ + static String map2Str(Map map) { + StringBuilder sb = new StringBuilder(); + Set 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; + } } \ No newline at end of file diff --git a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java index c083c46e..34c54227 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java @@ -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 urls) { + if (urls == null || urls.isEmpty()) { + throw new IllegalArgumentException("链接组不能为null"); + } + } + + /** + * 检查下载任务组保存路径 + */ + public static void checkDownloadPaths(List 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())) { diff --git a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java index 28d447ad..bceff11e 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java @@ -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 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 AbsCmd createCmd(String target, T entity, int cmd) { - return CmdFactory.getInstance().createCmd(target, entity, cmd); + public static AbsNormalCmd createCmd(String target, T entity, int cmd) { + return NormalCmdFactory.getInstance().createCmd(target, entity, cmd); } /** diff --git a/AriaAnnotations/build.gradle b/AriaAnnotations/build.gradle index 0b581ad5..a9f2139b 100644 --- a/AriaAnnotations/build.gradle +++ b/AriaAnnotations/build.gradle @@ -11,4 +11,4 @@ dependencies { compile fileTree(dir: 'libs', include: ['*.jar']) } -//apply from: 'bintray-release.gradle' \ No newline at end of file +apply from: 'bintray-release.gradle' \ No newline at end of file diff --git a/AriaCompiler/build.gradle b/AriaCompiler/build.gradle index 38de01a1..a76e8659 100644 --- a/AriaCompiler/build.gradle +++ b/AriaCompiler/build.gradle @@ -14,4 +14,4 @@ dependencies { compile project(':AriaAnnotations') } -//apply from: 'bintray-release.gradle' \ No newline at end of file +apply from: 'bintray-release.gradle' \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index cb5f0bd7..c0683d76 100644 --- a/app/build.gradle +++ b/app/build.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') } diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml index 9972caa4..474752d0 100644 --- a/app/src/main/assets/aria_config.xml +++ b/app/src/main/assets/aria_config.xml @@ -7,9 +7,6 @@ - - - @@ -40,8 +37,6 @@ - - diff --git a/app/src/main/java/com/arialyy/simple/download/DownloadModule.java b/app/src/main/java/com/arialyy/simple/download/DownloadModule.java index f4c2e831..56ad3738 100644 --- a/app/src/main/java/com/arialyy/simple/download/DownloadModule.java +++ b/app/src/main/java/com/arialyy/simple/download/DownloadModule.java @@ -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; - } - } - }; - } } \ No newline at end of file diff --git a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java index ecef722d..785e14a8 100644 --- a/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/SingleTaskActivity.java @@ -65,7 +65,7 @@ public class SingleTaskActivity extends BaseActivity { "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 { @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 { 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 { } 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(); diff --git a/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java b/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java index 502a5ce3..915472fa 100644 --- a/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java +++ b/app/src/main/java/com/arialyy/simple/download/multi_download/MultiDownloadActivity.java @@ -106,10 +106,7 @@ public class MultiDownloadActivity extends BaseActivity { +public class UploadTask extends AbsNormalTask { 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 { 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 outHandler; WeakReference 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 { } } - 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(); } } diff --git a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java index 84ea56f1..93edfe96 100644 --- a/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java +++ b/aria/src/main/java/com/arialyy/aria/core/upload/UploadTaskEntity.java @@ -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 { 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 formFields = new HashMap<>(); - public UploadTaskEntity(UploadEntity downloadEntity) { - this.uploadEntity = downloadEntity; + public UploadTaskEntity() { } @Override public UploadEntity getEntity() { - return uploadEntity; + return entity; } } diff --git a/build.gradle b/build.gradle index 36979409..1c332c62 100644 --- a/build.gradle +++ b/build.gradle @@ -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'