DownloadUtil 重命名为 Aria,代码已重构,使用起来更加简便
This commit is contained in:
3
Aria/.gitignore
vendored
Normal file
3
Aria/.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/build
|
||||
gradle.properties
|
||||
downloadutil.iml
|
26
Aria/build.gradle
Normal file
26
Aria/build.gradle
Normal file
@ -0,0 +1,26 @@
|
||||
apply plugin: 'com.android.library'
|
||||
|
||||
android {
|
||||
compileSdkVersion 23
|
||||
buildToolsVersion "23.0.2"
|
||||
|
||||
defaultConfig {
|
||||
minSdkVersion 9
|
||||
targetSdkVersion 23
|
||||
versionCode 58
|
||||
versionName "2.3.0"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
testCompile 'junit:junit:4.12'
|
||||
compile 'com.android.support:appcompat-v7:23.1.1'
|
||||
}
|
||||
apply from: 'jcenter.gradle'
|
142
Aria/jcenter.gradle
Normal file
142
Aria/jcenter.gradle
Normal file
@ -0,0 +1,142 @@
|
||||
group = PROJ_GROUP_ID
|
||||
version = PROJ_VERSION
|
||||
project.archivesBaseName = PROJ_ARTIFACT_ID
|
||||
apply plugin: 'com.jfrog.bintray'
|
||||
apply plugin: 'com.github.dcendents.android-maven'
|
||||
//输入:gradlew bintrayupload 执行
|
||||
|
||||
//############################## jar、sources、doc 打包 start #######################################
|
||||
task sourcesJar(type: Jar) {
|
||||
from android.sourceSets.main.java.srcDirs
|
||||
classifier = 'sources'
|
||||
}
|
||||
|
||||
task javadoc(type: Javadoc) {
|
||||
source = android.sourceSets.main.java.srcDirs
|
||||
classpath += configurations.compile
|
||||
classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
|
||||
}
|
||||
|
||||
task javadocJar(type: Jar, dependsOn: javadoc) {
|
||||
classifier = 'javadoc'
|
||||
from javadoc.destinationDir
|
||||
}
|
||||
|
||||
javadoc {
|
||||
options {
|
||||
encoding "UTF-8"
|
||||
charSet 'UTF-8'
|
||||
author true
|
||||
version true
|
||||
links "http://docs.oracle.com/javase/7/docs/api"
|
||||
title PROJ_ARTIFACT_ID
|
||||
}
|
||||
}
|
||||
|
||||
//添加以下信息避免JAVADOC打包时引用其它类库而出现问题,比如出现以下错误
|
||||
// xxxx.java:20: 错误: 找不到符号
|
||||
// public static <T> T create(JsonElement json, Class<T> classOfModel) {
|
||||
// ^
|
||||
// 符号: 类 JsonElement
|
||||
// 位置: 类 xxxx
|
||||
android.libraryVariants.all { variant ->
|
||||
println variant.javaCompile.classpath.files
|
||||
if (variant.name == 'release') {
|
||||
//我们只需 release 的 javadoc
|
||||
task("generate${variant.name.capitalize()}Javadoc", type: Javadoc) {
|
||||
// title = ''
|
||||
// description = ''
|
||||
source = variant.javaCompile.source
|
||||
classpath = files(variant.javaCompile.classpath.files, project.android.getBootClasspath())
|
||||
options {
|
||||
encoding "utf-8"
|
||||
links "http://docs.oracle.com/javase/7/docs/api/"
|
||||
linksOffline "http://d.android.com/reference", "${android.sdkDirectory}/docs/reference"
|
||||
}
|
||||
exclude '**/BuildConfig.java'
|
||||
exclude '**/R.java'
|
||||
}
|
||||
task("javadoc${variant.name.capitalize()}Jar", type: Jar,
|
||||
dependsOn: "generate${variant.name.capitalize()}Javadoc") {
|
||||
classifier = 'javadoc'
|
||||
from tasks.getByName("generate${variant.name.capitalize()}Javadoc").destinationDir
|
||||
}
|
||||
artifacts {
|
||||
archives tasks.getByName("javadoc${variant.name.capitalize()}Jar")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
artifacts {
|
||||
archives javadocJar
|
||||
archives sourcesJar
|
||||
}
|
||||
//############################## jar、sources、doc 打包 end #######################################
|
||||
|
||||
//################################# jcenter 上传配置 start #########################################
|
||||
bintray {
|
||||
user = hasProperty("bintrayUser") ? getProperty("bintrayUser") : getProperty("BINTRAY_USER")
|
||||
key = hasProperty("bintrayKey") ? getProperty("bintrayKey") : getProperty("BINTRAY_KEY")
|
||||
|
||||
configurations = ['archives']
|
||||
|
||||
pkg {
|
||||
repo = PROJ_REPO
|
||||
name = PROJ_NAME
|
||||
desc = PROJ_DESCRIPTION
|
||||
websiteUrl = PROJ_WEB_SITE_URL
|
||||
issueTrackerUrl = PROJ_ISSUE_TRACKER_URL
|
||||
vcsUrl = PROJ_VCS_URL
|
||||
publish = true
|
||||
publicDownloadNumbers = true
|
||||
licenses = LICENSES
|
||||
// version {
|
||||
// desc = libraryDescription
|
||||
// gpg {
|
||||
// sign = true //Determines whether to GPG sign the files. The default is false
|
||||
// passphrase = properties.getProperty("bintray.gpg.password")
|
||||
// //Optional. The passphrase for GPG signing'
|
||||
// }
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
//install
|
||||
install {
|
||||
repositories.mavenInstaller {
|
||||
// This generates POM.xml with proper parameters
|
||||
pom {
|
||||
project {
|
||||
packaging 'aar'
|
||||
groupId PROJ_GROUP_ID
|
||||
artifactId PROJ_ARTIFACT_ID
|
||||
|
||||
// Add your description here
|
||||
name PROJ_NAME
|
||||
description PROJ_DESCRIPTION
|
||||
url PROJ_WEB_SITE_URL
|
||||
|
||||
// Set your license
|
||||
licenses {
|
||||
license {
|
||||
name LICENSE_NAME
|
||||
url LICENSE_URL
|
||||
}
|
||||
}
|
||||
developers {
|
||||
developer {
|
||||
id DEVELOPER_ID
|
||||
name DEVELOPER_NAME
|
||||
email DEVELOPER_EMAIL
|
||||
}
|
||||
}
|
||||
scm {
|
||||
connection PROJ_WEB_SITE_URL
|
||||
developerConnection PROJ_WEB_SITE_URL
|
||||
url PROJ_VCS_URL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//################################# jcenter 上传配置 end #########################################
|
17
Aria/proguard-rules.pro
vendored
Normal file
17
Aria/proguard-rules.pro
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
# Add project specific ProGuard rules here.
|
||||
# By default, the flags in this file are appended to flags specified
|
||||
# in D:\sdk/tools/proguard/proguard-android.txt
|
||||
# You can edit the include path and order by changing the proguardFiles
|
||||
# directive in build.gradle.
|
||||
#
|
||||
# For more details, see
|
||||
# http://developer.android.com/guide/developing/tools/proguard.html
|
||||
|
||||
# Add any project specific keep options here:
|
||||
|
||||
# If your project uses WebView with JS, uncomment the following
|
||||
# and specify the fully qualified class name to the JavaScript interface
|
||||
# class:
|
||||
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
|
||||
# public *;
|
||||
#}
|
@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.downloadutil;
|
||||
|
||||
import android.app.Application;
|
||||
import android.test.ApplicationTestCase;
|
||||
|
||||
/**
|
||||
* <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
|
||||
*/
|
||||
public class ApplicationTest extends ApplicationTestCase<Application> {
|
||||
public ApplicationTest() {
|
||||
super(Application.class);
|
||||
}
|
||||
}
|
11
Aria/src/main/AndroidManifest.xml
Normal file
11
Aria/src/main/AndroidManifest.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.arialyy.aria">
|
||||
|
||||
<application
|
||||
android:allowBackup="true"
|
||||
android:label="@string/app_name"
|
||||
android:supportsRtl="true">
|
||||
|
||||
</application>
|
||||
|
||||
</manifest>
|
52
Aria/src/main/java/com/arialyy/aria/core/AMReceiver.java
Normal file
52
Aria/src/main/java/com/arialyy/aria/core/AMReceiver.java
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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;
|
||||
|
||||
import com.arialyy.aria.core.scheduler.OnSchedulerListener;
|
||||
|
||||
/**
|
||||
* AM 接收器
|
||||
*/
|
||||
public class AMReceiver {
|
||||
Object obj;
|
||||
OnSchedulerListener listener;
|
||||
DownloadEntity entity;
|
||||
DownloadManager manager = DownloadManager.getInstance();
|
||||
|
||||
public AMTarget load(DownloadEntity entity) {
|
||||
this.entity = entity;
|
||||
return new AMTarget(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加调度器回调
|
||||
*/
|
||||
public AMReceiver addSchedulerListener(OnSchedulerListener listener) {
|
||||
this.listener = listener;
|
||||
manager.getTaskQueue().getDownloadSchedulers().addSchedulerListener(obj, listener);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除回调
|
||||
*/
|
||||
public AMReceiver removeSchedulerListener() {
|
||||
if (listener != null) {
|
||||
manager.getTaskQueue().getDownloadSchedulers().removeSchedulerListener(obj, listener);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
97
Aria/src/main/java/com/arialyy/aria/core/AMTarget.java
Normal file
97
Aria/src/main/java/com/arialyy/aria/core/AMTarget.java
Normal file
@ -0,0 +1,97 @@
|
||||
package com.arialyy.aria.core;
|
||||
|
||||
import com.arialyy.aria.core.command.CmdFactory;
|
||||
import com.arialyy.aria.core.scheduler.OnSchedulerListener;
|
||||
import com.arialyy.aria.core.command.IDownloadCmd;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by utstarcom on 2016/12/5.
|
||||
*/
|
||||
public class AMTarget {
|
||||
private AMReceiver receiver;
|
||||
|
||||
public AMTarget(AMReceiver receiver) {
|
||||
this.receiver = receiver;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加任务
|
||||
*/
|
||||
public void add() {
|
||||
receiver.manager.setCmd(
|
||||
CommonUtil.createCmd(receiver.obj, receiver.entity, CmdFactory.TASK_CREATE)).exe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始下载
|
||||
*/
|
||||
public void start() {
|
||||
List<IDownloadCmd> cmds = new ArrayList<>();
|
||||
cmds.add(CommonUtil.createCmd(receiver.obj, receiver.entity, CmdFactory.TASK_CREATE));
|
||||
cmds.add(CommonUtil.createCmd(receiver.obj, receiver.entity, CmdFactory.TASK_START));
|
||||
receiver.manager.setCmds(cmds).exe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止下载
|
||||
*/
|
||||
public void stop() {
|
||||
receiver.manager.setCmd(
|
||||
CommonUtil.createCmd(receiver.obj, receiver.entity, CmdFactory.TASK_STOP)).exe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 恢复下载
|
||||
*/
|
||||
public void resume() {
|
||||
receiver.manager.setCmd(
|
||||
CommonUtil.createCmd(receiver.obj, receiver.entity, CmdFactory.TASK_START)).exe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
public void cancel() {
|
||||
receiver.manager.setCmd(
|
||||
CommonUtil.createCmd(receiver.obj, receiver.entity, CmdFactory.TASK_CANCEL)).exe();
|
||||
}
|
||||
|
||||
public static class SimpleSchedulerListener implements OnSchedulerListener {
|
||||
|
||||
@Override public void onTaskPre(Task task) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTaskResume(Task task) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTaskStart(Task task) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTaskStop(Task task) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTaskCancel(Task task) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTaskFail(Task task) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTaskComplete(Task task) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onTaskRunning(Task task) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
63
Aria/src/main/java/com/arialyy/aria/core/Aria.java
Normal file
63
Aria/src/main/java/com/arialyy/aria/core/Aria.java
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.app.Fragment;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/12/1.
|
||||
* Aria启动,管理全局任务
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1) public class Aria {
|
||||
|
||||
private Aria() {
|
||||
}
|
||||
|
||||
public static AMReceiver whit(Context context) {
|
||||
if (context == null) throw new IllegalArgumentException("context 不能为 null");
|
||||
if (context instanceof Activity
|
||||
|| context instanceof Service
|
||||
|| context instanceof Application) {
|
||||
return AriaManager.getInstance(context).get(context);
|
||||
} else {
|
||||
throw new IllegalArgumentException("这是不支持的context");
|
||||
}
|
||||
}
|
||||
|
||||
public static AMReceiver whit(Fragment fragment) {
|
||||
return AriaManager.getInstance(
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? fragment.getContext()
|
||||
: fragment.getActivity()).get(fragment);
|
||||
}
|
||||
|
||||
public static AriaManager get(Context context) {
|
||||
if (context == null) throw new IllegalArgumentException("context 不能为 null");
|
||||
if (context instanceof Activity
|
||||
|| context instanceof Service
|
||||
|| context instanceof Application) {
|
||||
return AriaManager.getInstance(context);
|
||||
} else {
|
||||
throw new IllegalArgumentException("这是不支持的context");
|
||||
}
|
||||
}
|
||||
}
|
164
Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
Normal file
164
Aria/src/main/java/com/arialyy/aria/core/AriaManager.java
Normal file
@ -0,0 +1,164 @@
|
||||
package com.arialyy.aria.core;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.Application;
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import com.arialyy.aria.core.command.CmdFactory;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.core.command.IDownloadCmd;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/12/1.
|
||||
* Aria管理器,任务操作在这里执行
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class AriaManager {
|
||||
private static final Object LOCK = new Object();
|
||||
private static volatile AriaManager INSTANCE = null;
|
||||
private Map<String, AMReceiver> mTargets = new HashMap<>();
|
||||
private DownloadManager mManager;
|
||||
private LifeCallback mLifeCallback;
|
||||
|
||||
private AriaManager(Context context) {
|
||||
regAppLifeCallback(context);
|
||||
mManager = DownloadManager.init(context);
|
||||
}
|
||||
|
||||
static AriaManager getInstance(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new AriaManager(context);
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
AMReceiver get(Object obj) {
|
||||
return getTarget(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置同时下载的任务数
|
||||
*/
|
||||
public void setDownloadNum(int num){
|
||||
if (num <= 0){
|
||||
throw new IllegalArgumentException("下载任务数不能小于1");
|
||||
}
|
||||
mManager.getTaskQueue().setDownloadNum(num);
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止所有正在执行的任务
|
||||
*/
|
||||
public void stopAllTask() {
|
||||
List<DownloadEntity> allEntity = mManager.getAllDownloadEntity();
|
||||
List<IDownloadCmd> stopCmds = new ArrayList<>();
|
||||
for (DownloadEntity entity : allEntity) {
|
||||
if (entity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
|
||||
stopCmds.add(CommonUtil.createCmd(entity, CmdFactory.TASK_STOP));
|
||||
}
|
||||
}
|
||||
mManager.setCmds(stopCmds).exe();
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除所有任务
|
||||
*/
|
||||
public void cancelAllTask() {
|
||||
List<DownloadEntity> allEntity = mManager.getAllDownloadEntity();
|
||||
List<IDownloadCmd> cancelCmds = new ArrayList<>();
|
||||
for (DownloadEntity entity : allEntity) {
|
||||
cancelCmds.add(CommonUtil.createCmd(entity, CmdFactory.TASK_CANCEL));
|
||||
}
|
||||
mManager.setCmds(cancelCmds).exe();
|
||||
Set<String> keys = mTargets.keySet();
|
||||
for (String key : keys) {
|
||||
AMReceiver target = mTargets.get(key);
|
||||
target.removeSchedulerListener();
|
||||
mTargets.remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
private AMReceiver putTarget(Object obj) {
|
||||
String clsName = obj.getClass().getName();
|
||||
AMReceiver target = mTargets.get(clsName);
|
||||
if (target == null) {
|
||||
target = new AMReceiver();
|
||||
target.obj = obj;
|
||||
mTargets.put(clsName, target);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
private AMReceiver getTarget(Object obj) {
|
||||
AMReceiver target = mTargets.get(obj.getClass().getName());
|
||||
if (target == null) {
|
||||
target = putTarget(obj);
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
/**
|
||||
* 注册APP生命周期回调
|
||||
*/
|
||||
private void regAppLifeCallback(Context context) {
|
||||
Context app = context.getApplicationContext();
|
||||
if (app instanceof Application) {
|
||||
mLifeCallback = new LifeCallback();
|
||||
((Application) app).registerActivityLifecycleCallbacks(mLifeCallback);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Activity生命周期
|
||||
*/
|
||||
private class LifeCallback implements Application.ActivityLifecycleCallbacks {
|
||||
|
||||
@Override public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onActivityStarted(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onActivityResumed(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onActivityPaused(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onActivityStopped(Activity activity) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onActivityDestroyed(Activity activity) {
|
||||
Set<String> keys = mTargets.keySet();
|
||||
for (String key : keys) {
|
||||
if (key.equals(activity.getClass().getName())) {
|
||||
AMReceiver target = mTargets.get(key);
|
||||
if (target.obj != null) {
|
||||
if (target.obj instanceof Application || target.obj instanceof Service) break;
|
||||
target.removeSchedulerListener();
|
||||
mTargets.remove(key);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
233
Aria/src/main/java/com/arialyy/aria/core/DownloadEntity.java
Normal file
233
Aria/src/main/java/com/arialyy/aria/core/DownloadEntity.java
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import com.arialyy.aria.orm.Ignore;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/12/25.
|
||||
* 下载实体
|
||||
* !!! 注意:CREATOR要进行@Ignore注解
|
||||
* !!!并且需要Parcelable时需要手动填写rowID;
|
||||
*/
|
||||
public class DownloadEntity extends DbEntity implements Parcelable {
|
||||
/**
|
||||
* 其它状态
|
||||
*/
|
||||
@Ignore public static final int STATE_OTHER = -1;
|
||||
/**
|
||||
* 失败状态
|
||||
*/
|
||||
@Ignore public static final int STATE_FAIL = 0;
|
||||
/**
|
||||
* 完成状态
|
||||
*/
|
||||
@Ignore public static final int STATE_COMPLETE = 1;
|
||||
/**
|
||||
* 停止状态
|
||||
*/
|
||||
@Ignore public static final int STATE_STOP = 2;
|
||||
/**
|
||||
* 未开始状态
|
||||
*/
|
||||
@Ignore public static final int STATE_WAIT = 3;
|
||||
/**
|
||||
* 下载中
|
||||
*/
|
||||
@Ignore public static final int STATE_DOWNLOAD_ING = 4;
|
||||
/**
|
||||
* 预处理
|
||||
*/
|
||||
@Ignore public static final int STATE_PRE = 5;
|
||||
/**
|
||||
* 预处理完成
|
||||
*/
|
||||
@Ignore public static final int STATE_POST_PRE = 6;
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
@Ignore public static final int STATE_CANCEL = 7;
|
||||
@Ignore public static final Creator<DownloadEntity> CREATOR = new Creator<DownloadEntity>() {
|
||||
@Override public DownloadEntity createFromParcel(Parcel source) {
|
||||
return new DownloadEntity(source);
|
||||
}
|
||||
|
||||
@Override public DownloadEntity[] newArray(int size) {
|
||||
return new DownloadEntity[size];
|
||||
}
|
||||
};
|
||||
@Ignore private long speed = 0; //下载速度
|
||||
@Ignore private int failNum = 0;
|
||||
private String downloadUrl = ""; //下载路径
|
||||
private String downloadPath = ""; //保存路径
|
||||
private String fileName = ""; //文件名
|
||||
private String str = ""; //其它字段
|
||||
private long fileSize = 1;
|
||||
private int state = STATE_WAIT;
|
||||
private boolean isDownloadComplete = false; //是否下载完成
|
||||
private long currentProgress = 0; //当前下载进度
|
||||
private long completeTime; //完成时间
|
||||
|
||||
public DownloadEntity() {
|
||||
}
|
||||
|
||||
protected DownloadEntity(Parcel in) {
|
||||
this.downloadUrl = in.readString();
|
||||
this.downloadPath = in.readString();
|
||||
this.fileName = in.readString();
|
||||
this.str = in.readString();
|
||||
this.completeTime = in.readLong();
|
||||
this.fileSize = in.readLong();
|
||||
this.state = in.readInt();
|
||||
this.isDownloadComplete = in.readByte() != 0;
|
||||
this.currentProgress = in.readLong();
|
||||
this.failNum = in.readInt();
|
||||
this.speed = in.readLong();
|
||||
this.rowID = in.readInt();
|
||||
}
|
||||
|
||||
public String getStr() {
|
||||
return str;
|
||||
}
|
||||
|
||||
public void setStr(String str) {
|
||||
this.str = str;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public DownloadEntity setFileName(String fileName) {
|
||||
this.fileName = fileName;
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFailNum() {
|
||||
return failNum;
|
||||
}
|
||||
|
||||
public void setFailNum(int failNum) {
|
||||
this.failNum = failNum;
|
||||
}
|
||||
|
||||
public String getDownloadUrl() {
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
public DownloadEntity setDownloadUrl(String downloadUrl) {
|
||||
this.downloadUrl = downloadUrl;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getCompleteTime() {
|
||||
return completeTime;
|
||||
}
|
||||
|
||||
public void setCompleteTime(long completeTime) {
|
||||
this.completeTime = completeTime;
|
||||
}
|
||||
|
||||
public String getDownloadPath() {
|
||||
return downloadPath;
|
||||
}
|
||||
|
||||
public DownloadEntity setDownloadPath(String downloadPath) {
|
||||
this.downloadPath = downloadPath;
|
||||
return this;
|
||||
}
|
||||
|
||||
public long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(long fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
public void setState(int state) {
|
||||
this.state = state;
|
||||
}
|
||||
|
||||
public boolean isDownloadComplete() {
|
||||
return isDownloadComplete;
|
||||
}
|
||||
|
||||
public void setDownloadComplete(boolean downloadComplete) {
|
||||
isDownloadComplete = downloadComplete;
|
||||
}
|
||||
|
||||
public long getSpeed() {
|
||||
return speed;
|
||||
}
|
||||
|
||||
public void setSpeed(long speed) {
|
||||
this.speed = speed;
|
||||
}
|
||||
|
||||
public long getCurrentProgress() {
|
||||
return currentProgress;
|
||||
}
|
||||
|
||||
public void setCurrentProgress(long currentProgress) {
|
||||
this.currentProgress = currentProgress;
|
||||
}
|
||||
|
||||
@Override public DownloadEntity clone() throws CloneNotSupportedException {
|
||||
return (DownloadEntity) super.clone();
|
||||
}
|
||||
|
||||
@Override public String toString() {
|
||||
return "DownloadEntity{" +
|
||||
"downloadUrl='" + downloadUrl + '\'' +
|
||||
", downloadPath='" + downloadPath + '\'' +
|
||||
", completeTime=" + completeTime +
|
||||
", fileSize=" + fileSize +
|
||||
", state=" + state +
|
||||
", isDownloadComplete=" + isDownloadComplete +
|
||||
", currentProgress=" + currentProgress +
|
||||
", failNum=" + failNum +
|
||||
'}';
|
||||
}
|
||||
|
||||
@Override public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(this.downloadUrl);
|
||||
dest.writeString(this.downloadPath);
|
||||
dest.writeString(this.fileName);
|
||||
dest.writeString(this.str);
|
||||
dest.writeLong(this.completeTime);
|
||||
dest.writeLong(this.fileSize);
|
||||
dest.writeInt(this.state);
|
||||
dest.writeByte(this.isDownloadComplete ? (byte) 1 : (byte) 0);
|
||||
dest.writeLong(this.currentProgress);
|
||||
dest.writeInt(this.failNum);
|
||||
dest.writeLong(this.speed);
|
||||
dest.writeInt(this.rowID);
|
||||
}
|
||||
}
|
153
Aria/src/main/java/com/arialyy/aria/core/DownloadManager.java
Normal file
153
Aria/src/main/java/com/arialyy/aria/core/DownloadManager.java
Normal file
@ -0,0 +1,153 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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;
|
||||
|
||||
import android.content.Context;
|
||||
import com.arialyy.aria.core.queue.ITaskQueue;
|
||||
import com.arialyy.aria.orm.DbUtil;
|
||||
import com.arialyy.aria.core.command.IDownloadCmd;
|
||||
import com.arialyy.aria.core.queue.DownloadTaskQueue;
|
||||
import com.arialyy.aria.orm.DbEntity;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/11.
|
||||
* 下载管理器,通过命令的方式控制下载
|
||||
*/
|
||||
public class DownloadManager {
|
||||
/**
|
||||
* 预处理完成
|
||||
*/
|
||||
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 ENTITY = "DOWNLOAD_ENTITY";
|
||||
/**
|
||||
* 位置
|
||||
*/
|
||||
public static final String CURRENT_LOCATION = "CURRENT_LOCATION";
|
||||
/**
|
||||
* 速度
|
||||
*/
|
||||
public static final String CURRENT_SPEED = "CURRENT_SPEED";
|
||||
private static final String TAG = "DownloadManager";
|
||||
private static final Object LOCK = new Object();
|
||||
private static volatile DownloadManager INSTANCE = null;
|
||||
private List<IDownloadCmd> mCommands = new ArrayList<>();
|
||||
private Context mContext;
|
||||
private ITaskQueue mTaskQueue;
|
||||
|
||||
private DownloadManager() {
|
||||
|
||||
}
|
||||
|
||||
private DownloadManager(Context context) {
|
||||
mContext = context;
|
||||
DownloadTaskQueue.Builder builder = new DownloadTaskQueue.Builder(context);
|
||||
mTaskQueue = builder.build();
|
||||
DbUtil.init(context);
|
||||
}
|
||||
|
||||
public static DownloadManager init(Context context) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new DownloadManager(context.getApplicationContext());
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public static DownloadManager getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
throw new NullPointerException("请在Application中调用init进行下载器注册");
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public List<DownloadEntity> getAllDownloadEntity() {
|
||||
return DbEntity.findAllData(DownloadEntity.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务队列
|
||||
*/
|
||||
public ITaskQueue getTaskQueue() {
|
||||
return mTaskQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置命令
|
||||
*/
|
||||
public DownloadManager setCmd(IDownloadCmd command) {
|
||||
mCommands.add(command);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置一组命令
|
||||
*/
|
||||
public DownloadManager setCmds(List<IDownloadCmd> commands) {
|
||||
if (commands != null && commands.size() > 0) {
|
||||
mCommands.addAll(commands);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行所有设置的命令
|
||||
*/
|
||||
public synchronized void exe() {
|
||||
for (IDownloadCmd command : mCommands) {
|
||||
command.executeCmd();
|
||||
}
|
||||
mCommands.clear();
|
||||
}
|
||||
}
|
45
Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
Normal file
45
Aria/src/main/java/com/arialyy/aria/core/command/AddCmd.java
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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 android.util.Log;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/22.
|
||||
* 添加任务的命令
|
||||
*/
|
||||
class AddCmd extends IDownloadCmd {
|
||||
|
||||
AddCmd(DownloadEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
AddCmd(Object target, DownloadEntity entity) {
|
||||
super(target, entity);
|
||||
}
|
||||
|
||||
@Override public void executeCmd() {
|
||||
Task task = mQueue.getTask(mEntity);
|
||||
if (task == null) {
|
||||
mQueue.createTask(mTarget, mEntity);
|
||||
} else {
|
||||
Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.DownloadEntity;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/9/20.
|
||||
* 取消命令
|
||||
*/
|
||||
class CancelCmd extends IDownloadCmd {
|
||||
|
||||
CancelCmd(Object target, DownloadEntity entity) {
|
||||
super(target, entity);
|
||||
}
|
||||
|
||||
CancelCmd(DownloadEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override public void executeCmd() {
|
||||
Task task = mQueue.getTask(mEntity);
|
||||
if (task == null) {
|
||||
task = mQueue.createTask(mTarget, mEntity);
|
||||
}
|
||||
if (task != null) {
|
||||
task.setmTargetName(mTarget.getClass().getName());
|
||||
mQueue.cancelTask(task);
|
||||
}
|
||||
}
|
||||
}
|
182
Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java
Normal file
182
Aria/src/main/java/com/arialyy/aria/core/command/CmdFactory.java
Normal file
@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.DownloadEntity;
|
||||
|
||||
/**
|
||||
* Created by Lyy on 2016/9/23.
|
||||
* 命令工厂
|
||||
*/
|
||||
public class CmdFactory {
|
||||
/**
|
||||
* 创建任务
|
||||
*/
|
||||
public static final int TASK_CREATE = 0x122;
|
||||
/**
|
||||
* 启动任务
|
||||
*/
|
||||
public static final int TASK_START = 0x123;
|
||||
/**
|
||||
* 恢复任务
|
||||
*/
|
||||
public static final int TASK_RESUME = 0x127;
|
||||
/**
|
||||
* 取消任务
|
||||
*/
|
||||
public static final int TASK_CANCEL = 0x124;
|
||||
/**
|
||||
* 停止任务
|
||||
*/
|
||||
public static final int TASK_STOP = 0x125;
|
||||
public static final int TASK_SINGLE = 0x126;
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
private static volatile CmdFactory INSTANCE = null;
|
||||
|
||||
private CmdFactory() {
|
||||
|
||||
}
|
||||
|
||||
public static CmdFactory getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new CmdFactory();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param entity 下载实体
|
||||
* @param type 命令类型{@link #TASK_CREATE}、{@link #TASK_START}、{@link #TASK_CANCEL}、{@link
|
||||
* #TASK_STOP}
|
||||
*/
|
||||
public IDownloadCmd createCmd(DownloadEntity entity, int type) {
|
||||
switch (type) {
|
||||
case TASK_CREATE:
|
||||
return createAddCmd(entity);
|
||||
case TASK_RESUME:
|
||||
case TASK_START:
|
||||
return createStartCmd(entity);
|
||||
case TASK_CANCEL:
|
||||
return createCancelCmd(entity);
|
||||
case TASK_STOP:
|
||||
return createStopCmd(entity);
|
||||
case TASK_SINGLE:
|
||||
return new SingleCmd(entity);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param target 创建任务的对象
|
||||
* @param entity 下载实体
|
||||
* @param type 命令类型{@link #TASK_CREATE}、{@link #TASK_START}、{@link #TASK_CANCEL}、{@link
|
||||
* #TASK_STOP}
|
||||
*/
|
||||
public IDownloadCmd createCmd(Object target, DownloadEntity entity, int type) {
|
||||
switch (type) {
|
||||
case TASK_CREATE:
|
||||
return createAddCmd(target, entity);
|
||||
case TASK_RESUME:
|
||||
case TASK_START:
|
||||
return createStartCmd(target, entity);
|
||||
case TASK_CANCEL:
|
||||
return createCancelCmd(target, entity);
|
||||
case TASK_STOP:
|
||||
return createStopCmd(target, entity);
|
||||
case TASK_SINGLE:
|
||||
return new SingleCmd(target, entity);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建停止命令
|
||||
*
|
||||
* @return {@link StopCmd}
|
||||
*/
|
||||
private StopCmd createStopCmd(Object target, DownloadEntity entity) {
|
||||
return new StopCmd(target, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建停止命令
|
||||
*
|
||||
* @return {@link StopCmd}
|
||||
*/
|
||||
private StopCmd createStopCmd(DownloadEntity entity) {
|
||||
return new StopCmd(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建下载任务命令
|
||||
*
|
||||
* @return {@link AddCmd}
|
||||
*/
|
||||
private AddCmd createAddCmd(Object target, DownloadEntity entity) {
|
||||
return new AddCmd(target, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建下载任务命令
|
||||
*
|
||||
* @return {@link AddCmd}
|
||||
*/
|
||||
private AddCmd createAddCmd(DownloadEntity entity) {
|
||||
return new AddCmd(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建启动下载命令
|
||||
*
|
||||
* @return {@link StartCmd}
|
||||
*/
|
||||
private StartCmd createStartCmd(Object target, DownloadEntity entity) {
|
||||
return new StartCmd(target, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建启动下载命令
|
||||
*
|
||||
* @return {@link StartCmd}
|
||||
*/
|
||||
private StartCmd createStartCmd(DownloadEntity entity) {
|
||||
return new StartCmd(entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 取消下载的命令
|
||||
*
|
||||
* @return {@link CancelCmd}
|
||||
*/
|
||||
private CancelCmd createCancelCmd(Object target, DownloadEntity entity) {
|
||||
return new CancelCmd(target, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 取消下载的命令
|
||||
*
|
||||
* @return {@link CancelCmd}
|
||||
*/
|
||||
private CancelCmd createCancelCmd(DownloadEntity entity) {
|
||||
return new CancelCmd(entity);
|
||||
}
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.DownloadManager;
|
||||
import com.arialyy.aria.core.queue.ITaskQueue;
|
||||
import com.arialyy.aria.util.CheckUtil;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/22.
|
||||
* 下载命令
|
||||
*/
|
||||
public abstract class IDownloadCmd {
|
||||
ITaskQueue mQueue;
|
||||
DownloadEntity mEntity;
|
||||
String TAG;
|
||||
Object mTarget;
|
||||
|
||||
/**
|
||||
* @param entity 下载实体
|
||||
*/
|
||||
IDownloadCmd(DownloadEntity entity) {
|
||||
this(null, entity);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param target 产生任务的对象
|
||||
*/
|
||||
IDownloadCmd(Object target, DownloadEntity entity) {
|
||||
if (!CheckUtil.checkDownloadEntity(entity)) {
|
||||
return;
|
||||
}
|
||||
mTarget = target;
|
||||
mEntity = entity;
|
||||
TAG = CommonUtil.getClassName(this);
|
||||
mQueue = DownloadManager.getInstance().getTaskQueue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行命令
|
||||
*/
|
||||
public abstract void executeCmd();
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package com.arialyy.aria.core.command;
|
||||
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/11/30.
|
||||
* 获取任务状态命令
|
||||
*/
|
||||
class SingleCmd extends IDownloadCmd {
|
||||
/**
|
||||
* @param entity 下载实体
|
||||
*/
|
||||
SingleCmd(Object target, DownloadEntity entity) {
|
||||
super(target, entity);
|
||||
}
|
||||
|
||||
SingleCmd(DownloadEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override public void executeCmd() {
|
||||
Task task = mQueue.getTask(mEntity);
|
||||
if (task == null) {
|
||||
task = mQueue.createTask(mTarget, mEntity);
|
||||
} else {
|
||||
Log.w(TAG, "添加命令执行失败,【该任务已经存在】");
|
||||
}
|
||||
task.setmTargetName(mTarget.getClass().getName());
|
||||
mQueue.startTask(task);
|
||||
}
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.DownloadEntity;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/22.
|
||||
* 开始命令
|
||||
*/
|
||||
class StartCmd extends IDownloadCmd {
|
||||
|
||||
StartCmd(Object target, DownloadEntity entity) {
|
||||
super(target, entity);
|
||||
}
|
||||
|
||||
StartCmd(DownloadEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override public void executeCmd() {
|
||||
Task task = mQueue.getTask(mEntity);
|
||||
if (task == null) {
|
||||
task = mQueue.createTask(mTarget, mEntity);
|
||||
}
|
||||
if (task != null) {
|
||||
task.setmTargetName(mTarget.getClass().getName());
|
||||
mQueue.startTask(task);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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 android.util.Log;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/9/20.
|
||||
* 停止命令
|
||||
*/
|
||||
class StopCmd extends IDownloadCmd {
|
||||
|
||||
/**
|
||||
* @param entity 下载实体
|
||||
*/
|
||||
StopCmd(Object target, DownloadEntity entity) {
|
||||
super(target, entity);
|
||||
}
|
||||
|
||||
StopCmd(DownloadEntity entity) {
|
||||
super(entity);
|
||||
}
|
||||
|
||||
@Override public void executeCmd() {
|
||||
Task task = mQueue.getTask(mEntity);
|
||||
if (task == null) {
|
||||
if (mEntity.getState() == DownloadEntity.STATE_DOWNLOAD_ING) {
|
||||
task = mQueue.createTask(mTarget, mEntity);
|
||||
mQueue.stopTask(task);
|
||||
} else {
|
||||
Log.w(TAG, "停止命令执行失败,【调度器中没有该任务】");
|
||||
}
|
||||
} else {
|
||||
task.setmTargetName(mTarget.getClass().getName());
|
||||
mQueue.stopTask(task);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,193 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.core.queue;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.queue.pool.CachePool;
|
||||
import com.arialyy.aria.core.queue.pool.ExecutePool;
|
||||
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
||||
import com.arialyy.aria.core.scheduler.IDownloadSchedulers;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
import com.arialyy.aria.core.task.TaskFactory;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/17.
|
||||
* 下载任务队列
|
||||
*/
|
||||
public class DownloadTaskQueue implements ITaskQueue {
|
||||
private static final String TAG = "DownloadTaskQueue";
|
||||
private CachePool mCachePool = CachePool.getInstance();
|
||||
private ExecutePool mExecutePool = ExecutePool.getInstance();
|
||||
private Context mContext;
|
||||
private IDownloadSchedulers mSchedulers;
|
||||
private int mDownloadNum = 2;
|
||||
|
||||
private DownloadTaskQueue() {
|
||||
}
|
||||
|
||||
private DownloadTaskQueue(Context context) {
|
||||
super();
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取任务执行池
|
||||
*/
|
||||
public ExecutePool getExecutePool() {
|
||||
return mExecutePool;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存池
|
||||
*/
|
||||
public CachePool getCachePool() {
|
||||
return mCachePool;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前运行的任务数
|
||||
*
|
||||
* @return 当前正在执行的任务数
|
||||
*/
|
||||
public int getCurrentTaskNum() {
|
||||
return mExecutePool.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存任务数
|
||||
*
|
||||
* @return 获取缓存的任务数
|
||||
*/
|
||||
public int getCacheTaskNum() {
|
||||
return mCachePool.size();
|
||||
}
|
||||
|
||||
@Override public void startTask(Task task) {
|
||||
if (mExecutePool.putTask(task)) {
|
||||
mCachePool.removeTask(task);
|
||||
task.getDownloadEntity().setFailNum(0);
|
||||
task.start();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void stopTask(Task task) {
|
||||
if (!task.isDownloading()) Log.w(TAG, "停止任务失败,【任务已经停止】");
|
||||
task.stop();
|
||||
//if (task.isDownloading()) {
|
||||
// if (mExecutePool.removeTask(task)) {
|
||||
// task.stop();
|
||||
// }
|
||||
//} else {
|
||||
// task.stop();
|
||||
// Log.w(TAG, "停止任务失败,【任务已经停止】");
|
||||
//}
|
||||
}
|
||||
|
||||
@Override public void cancelTask(Task task) {
|
||||
//if (mExecutePool.removeTask(task) || mCachePool.removeTask(task)) {
|
||||
// task.cancel();
|
||||
//}
|
||||
task.cancel();
|
||||
}
|
||||
|
||||
@Override public void reTryStart(Task task) {
|
||||
if (!task.isDownloading()) {
|
||||
task.start();
|
||||
} else {
|
||||
Log.w(TAG, "任务没有完全停止,重试下载失败");
|
||||
}
|
||||
}
|
||||
|
||||
@Override public IDownloadSchedulers getDownloadSchedulers() {
|
||||
return mSchedulers;
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return mExecutePool.size();
|
||||
}
|
||||
|
||||
@Override public void setDownloadNum(int downloadNum) {
|
||||
mExecutePool.setDownloadNum(downloadNum);
|
||||
}
|
||||
|
||||
@Override public Task createTask(Object target, DownloadEntity entity) {
|
||||
Task task;
|
||||
if (target == null) {
|
||||
task = TaskFactory.getInstance().createTask(mContext, entity, mSchedulers);
|
||||
} else {
|
||||
task = TaskFactory.getInstance()
|
||||
.createTask(target.getClass().getName(), mContext, entity, mSchedulers);
|
||||
}
|
||||
mCachePool.putTask(task);
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override public Task getTask(DownloadEntity entity) {
|
||||
Task task = mExecutePool.getTask(entity.getDownloadUrl());
|
||||
if (task == null) {
|
||||
task = mCachePool.getTask(entity.getDownloadUrl());
|
||||
}
|
||||
return task;
|
||||
}
|
||||
|
||||
@Override public void removeTask(DownloadEntity entity) {
|
||||
Task task = mExecutePool.getTask(entity.getDownloadUrl());
|
||||
if (task != null) {
|
||||
Log.d(TAG, "从执行池删除任务,删除" + (mExecutePool.removeTask(task) ? "成功" : "失败"));
|
||||
} else {
|
||||
task = mCachePool.getTask(entity.getDownloadUrl());
|
||||
}
|
||||
if (task != null) {
|
||||
Log.d(TAG, "从缓存池删除任务,删除" + (mCachePool.removeTask(task) ? "成功" : "失败"));
|
||||
} else {
|
||||
Log.w(TAG, "没有找到下载链接为【" + entity.getDownloadUrl() + "】的任务");
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Task getNextTask() {
|
||||
return mCachePool.pollTask();
|
||||
}
|
||||
|
||||
@Override public void setScheduler(IDownloadSchedulers schedulers) {
|
||||
mSchedulers = schedulers;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
Context context;
|
||||
IDownloadSchedulers schedulers;
|
||||
|
||||
public Builder(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
public Builder setDownloadSchedulers(IDownloadSchedulers schedulers) {
|
||||
this.schedulers = schedulers;
|
||||
return this;
|
||||
}
|
||||
|
||||
public DownloadTaskQueue build() {
|
||||
DownloadTaskQueue queue = new DownloadTaskQueue(context);
|
||||
if (schedulers == null) {
|
||||
schedulers = DownloadSchedulers.getInstance(queue);
|
||||
}
|
||||
queue.setScheduler(schedulers);
|
||||
return queue;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.arialyy.aria.core.queue;
|
||||
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/16.
|
||||
* 下载功能接口
|
||||
*/
|
||||
public interface IDownloader {
|
||||
/**
|
||||
* 开始任务
|
||||
*
|
||||
* @param task {@link Task}
|
||||
*/
|
||||
public void startTask(Task task);
|
||||
|
||||
/**
|
||||
* 停止任务
|
||||
*
|
||||
* @param task {@link Task}
|
||||
*/
|
||||
public void stopTask(Task task);
|
||||
|
||||
/**
|
||||
* 取消任务
|
||||
*
|
||||
* @param task {@link Task}
|
||||
*/
|
||||
public void cancelTask(Task task);
|
||||
|
||||
/**
|
||||
* 重试下载
|
||||
*
|
||||
* @param task {@link Task}
|
||||
*/
|
||||
public void reTryStart(Task task);
|
||||
}
|
69
Aria/src/main/java/com/arialyy/aria/core/queue/IPool.java
Normal file
69
Aria/src/main/java/com/arialyy/aria/core/queue/IPool.java
Normal file
@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
|
||||
package com.arialyy.aria.core.queue;
|
||||
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/14.
|
||||
* 任务池
|
||||
*/
|
||||
public interface IPool {
|
||||
/**
|
||||
* 将下载任务添加到任务池中
|
||||
*/
|
||||
public boolean putTask(Task task);
|
||||
|
||||
/**
|
||||
* 按照队列原则取出下载任务
|
||||
*
|
||||
* @return 返回null或者下载任务
|
||||
*/
|
||||
public Task pollTask();
|
||||
|
||||
/**
|
||||
* 通过下载链接获取下载任务,当任务不为空时,队列将删除该下载任务
|
||||
*
|
||||
* @param downloadUrl 下载链接
|
||||
* @return 返回null或者下载任务
|
||||
*/
|
||||
public Task getTask(String downloadUrl);
|
||||
|
||||
/**
|
||||
* 删除任务池中的下载任务
|
||||
*
|
||||
* @param task 下载任务
|
||||
* @return true:移除成功
|
||||
*/
|
||||
public boolean removeTask(Task task);
|
||||
|
||||
/**
|
||||
* 通过下载链接移除下载任务
|
||||
*
|
||||
* @param downloadUrl 下载链接
|
||||
* @return true:移除成功
|
||||
*/
|
||||
public boolean removeTask(String downloadUrl);
|
||||
|
||||
/**
|
||||
* 池子大小
|
||||
*
|
||||
* @return 返回缓存池或者当前任务池大小
|
||||
*/
|
||||
public int size();
|
||||
}
|
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.core.queue;
|
||||
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.scheduler.IDownloadSchedulers;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/16.
|
||||
* 任务功能接口
|
||||
*/
|
||||
public interface ITaskQueue extends IDownloader {
|
||||
|
||||
/**
|
||||
* 获取调度器
|
||||
*/
|
||||
public IDownloadSchedulers getDownloadSchedulers();
|
||||
|
||||
/**
|
||||
* 任务池队列大小
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* 设置下载任务数
|
||||
*
|
||||
* @param downloadNum 下载任务数
|
||||
*/
|
||||
public void setDownloadNum(int downloadNum);
|
||||
|
||||
/**
|
||||
* 创建一个新的下载任务,创建时只是将新任务存储到缓存池
|
||||
*
|
||||
* @param entity 下载实体{@link DownloadEntity}
|
||||
* @param target 生成该任务的对象
|
||||
* @return {@link Task}
|
||||
*/
|
||||
public Task createTask(Object target, DownloadEntity entity);
|
||||
|
||||
/**
|
||||
* 通过下载链接从缓存池或任务池搜索下载任务,如果缓存池或任务池都没有任务,则创建新任务
|
||||
*
|
||||
* @param entity 下载实体{@link DownloadEntity}
|
||||
* @return {@link Task}
|
||||
*/
|
||||
public Task getTask(DownloadEntity entity);
|
||||
|
||||
/**
|
||||
* 通过下载链接删除任务
|
||||
*
|
||||
* @param entity 下载实体{@link DownloadEntity}
|
||||
*/
|
||||
public void removeTask(DownloadEntity entity);
|
||||
|
||||
/**
|
||||
* 获取缓存池的下一个任务
|
||||
*
|
||||
* @return 下载任务 or null
|
||||
*/
|
||||
public Task getNextTask();
|
||||
|
||||
/**
|
||||
* 设置下载调度器
|
||||
*
|
||||
* @param schedulers 下载调度器{@link IDownloadSchedulers}
|
||||
*/
|
||||
public void setScheduler(IDownloadSchedulers schedulers);
|
||||
}
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.queue.IPool;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/14.
|
||||
* 任务缓存池,所有下载任务最先缓存在这个池中
|
||||
*/
|
||||
public class CachePool implements IPool {
|
||||
private static final String TAG = "CachePool";
|
||||
private static final Object LOCK = new Object();
|
||||
private static final int MAX_NUM = Integer.MAX_VALUE; //最大下载任务数
|
||||
private static volatile CachePool INSTANCE = null;
|
||||
private Map<String, Task> mCacheArray;
|
||||
private LinkedBlockingQueue<Task> mCacheQueue;
|
||||
|
||||
private CachePool() {
|
||||
mCacheQueue = new LinkedBlockingQueue<>(MAX_NUM);
|
||||
mCacheArray = new HashMap<>();
|
||||
}
|
||||
|
||||
public static CachePool getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new CachePool();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override public boolean putTask(Task task) {
|
||||
synchronized (LOCK) {
|
||||
if (task == null) {
|
||||
Log.e(TAG, "下载任务不能为空!!");
|
||||
return false;
|
||||
}
|
||||
String url = task.getDownloadEntity().getDownloadUrl();
|
||||
if (mCacheQueue.contains(task)) {
|
||||
Log.w(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】");
|
||||
return false;
|
||||
} else {
|
||||
boolean s = mCacheQueue.offer(task);
|
||||
Log.d(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
|
||||
if (s) {
|
||||
mCacheArray.put(CommonUtil.keyToHashKey(url), task);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Task pollTask() {
|
||||
synchronized (LOCK) {
|
||||
Task task = mCacheQueue.poll();
|
||||
if (task != null) {
|
||||
String url = task.getDownloadEntity().getDownloadUrl();
|
||||
mCacheArray.remove(CommonUtil.keyToHashKey(url));
|
||||
}
|
||||
return task;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Task getTask(String downloadUrl) {
|
||||
synchronized (LOCK) {
|
||||
if (TextUtils.isEmpty(downloadUrl)) {
|
||||
Log.e(TAG, "请传入有效的下载链接");
|
||||
return null;
|
||||
}
|
||||
String key = CommonUtil.keyToHashKey(downloadUrl);
|
||||
return mCacheArray.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean removeTask(Task task) {
|
||||
synchronized (LOCK) {
|
||||
if (task == null) {
|
||||
Log.e(TAG, "任务不能为空");
|
||||
return false;
|
||||
} else {
|
||||
String key = CommonUtil.keyToHashKey(task.getDownloadEntity().getDownloadUrl());
|
||||
mCacheArray.remove(key);
|
||||
return mCacheQueue.remove(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean removeTask(String downloadUrl) {
|
||||
synchronized (LOCK) {
|
||||
if (TextUtils.isEmpty(downloadUrl)) {
|
||||
Log.e(TAG, "请传入有效的下载链接");
|
||||
return false;
|
||||
}
|
||||
String key = CommonUtil.keyToHashKey(downloadUrl);
|
||||
Task task = mCacheArray.get(key);
|
||||
mCacheArray.remove(key);
|
||||
return mCacheQueue.remove(task);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return mCacheQueue.size();
|
||||
}
|
||||
}
|
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import com.arialyy.aria.core.queue.IPool;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
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 Object LOCK = new Object();
|
||||
private static final long TIME_OUT = 1000;
|
||||
private static volatile ExecutePool INSTANCE = null;
|
||||
public static int mSize = 2;
|
||||
private ArrayBlockingQueue<Task> mExecuteQueue;
|
||||
private Map<String, Task> mExecuteArray;
|
||||
|
||||
private ExecutePool() {
|
||||
mExecuteQueue = new ArrayBlockingQueue<>(mSize);
|
||||
mExecuteArray = new HashMap<>();
|
||||
}
|
||||
|
||||
public static ExecutePool getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new ExecutePool();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override public boolean putTask(Task task) {
|
||||
synchronized (LOCK) {
|
||||
if (task == null) {
|
||||
Log.e(TAG, "下载任务不能为空!!");
|
||||
return false;
|
||||
}
|
||||
String url = task.getDownloadEntity().getDownloadUrl();
|
||||
if (mExecuteQueue.contains(task)) {
|
||||
Log.e(TAG, "队列中已经包含了该任务,任务下载链接【" + url + "】");
|
||||
return false;
|
||||
} else {
|
||||
if (mExecuteQueue.size() >= mSize) {
|
||||
if (pollFirstTask()) {
|
||||
return putNewTask(task);
|
||||
}
|
||||
} else {
|
||||
return putNewTask(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置执行任务数
|
||||
*
|
||||
* @param downloadNum 下载数
|
||||
*/
|
||||
public void setDownloadNum(int downloadNum) {
|
||||
try {
|
||||
ArrayBlockingQueue<Task> temp = new ArrayBlockingQueue<>(downloadNum);
|
||||
Task task;
|
||||
while ((task = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS)) != null) {
|
||||
temp.offer(task);
|
||||
}
|
||||
mExecuteQueue = temp;
|
||||
mSize = downloadNum;
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加新任务
|
||||
*
|
||||
* @param newTask 新下载任务
|
||||
*/
|
||||
private boolean putNewTask(Task newTask) {
|
||||
String url = newTask.getDownloadEntity().getDownloadUrl();
|
||||
boolean s = mExecuteQueue.offer(newTask);
|
||||
Log.w(TAG, "任务添加" + (s ? "成功" : "失败,【" + url + "】"));
|
||||
if (s) {
|
||||
newTask.start();
|
||||
mExecuteArray.put(CommonUtil.keyToHashKey(url), newTask);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* 队列满时,将移除下载队列中的第一个任务
|
||||
*/
|
||||
private boolean pollFirstTask() {
|
||||
try {
|
||||
Task oldTask = mExecuteQueue.poll(TIME_OUT, TimeUnit.MICROSECONDS);
|
||||
if (oldTask == null) {
|
||||
Log.e(TAG, "移除任务失败");
|
||||
return false;
|
||||
}
|
||||
oldTask.stop();
|
||||
// wait(200);
|
||||
String key = CommonUtil.keyToHashKey(oldTask.getDownloadEntity().getDownloadUrl());
|
||||
mExecuteArray.remove(key);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override public Task pollTask() {
|
||||
synchronized (LOCK) {
|
||||
Task task = mExecuteQueue.poll();
|
||||
if (task != null) {
|
||||
String url = task.getDownloadEntity().getDownloadUrl();
|
||||
mExecuteArray.remove(CommonUtil.keyToHashKey(url));
|
||||
}
|
||||
return task;
|
||||
}
|
||||
}
|
||||
|
||||
@Override public Task getTask(String downloadUrl) {
|
||||
synchronized (LOCK) {
|
||||
if (TextUtils.isEmpty(downloadUrl)) {
|
||||
Log.e(TAG, "请传入有效的下载链接");
|
||||
return null;
|
||||
}
|
||||
String key = CommonUtil.keyToHashKey(downloadUrl);
|
||||
return mExecuteArray.get(key);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean removeTask(Task task) {
|
||||
synchronized (LOCK) {
|
||||
if (task == null) {
|
||||
Log.e(TAG, "任务不能为空");
|
||||
return false;
|
||||
} else {
|
||||
String key = CommonUtil.keyToHashKey(task.getDownloadEntity().getDownloadUrl());
|
||||
mExecuteArray.remove(key);
|
||||
return mExecuteQueue.remove(task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override public boolean removeTask(String downloadUrl) {
|
||||
synchronized (LOCK) {
|
||||
if (TextUtils.isEmpty(downloadUrl)) {
|
||||
Log.e(TAG, "请传入有效的下载链接");
|
||||
return false;
|
||||
}
|
||||
String key = CommonUtil.keyToHashKey(downloadUrl);
|
||||
Task task = mExecuteArray.get(key);
|
||||
mExecuteArray.remove(key);
|
||||
return mExecuteQueue.remove(task);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public int size() {
|
||||
return mExecuteQueue.size();
|
||||
}
|
||||
}
|
@ -0,0 +1,238 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.core.scheduler;
|
||||
|
||||
import android.os.Message;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.queue.ITaskQueue;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
import com.arialyy.aria.core.queue.pool.ExecutePool;
|
||||
import com.arialyy.aria.core.queue.DownloadTaskQueue;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/16.
|
||||
* 任务下载器,提供抽象的方法供具体的实现类操作
|
||||
*/
|
||||
public class DownloadSchedulers implements IDownloadSchedulers {
|
||||
/**
|
||||
* 任务预加载
|
||||
*/
|
||||
public static final int PRE = 0;
|
||||
/**
|
||||
* 任务开始
|
||||
*/
|
||||
public static final int START = 1;
|
||||
/**
|
||||
* 任务停止
|
||||
*/
|
||||
public static final int STOP = 2;
|
||||
/**
|
||||
* 任务失败
|
||||
*/
|
||||
public static final int FAIL = 3;
|
||||
/**
|
||||
* 任务取消
|
||||
*/
|
||||
public static final int CANCEL = 4;
|
||||
/**
|
||||
* 任务完成
|
||||
*/
|
||||
public static final int COMPLETE = 5;
|
||||
/**
|
||||
* 下载中
|
||||
*/
|
||||
public static final int RUNNING = 6;
|
||||
/**
|
||||
* 恢复下载
|
||||
*/
|
||||
public static final int RESUME = 7;
|
||||
private static final String TAG = "DownloadSchedulers";
|
||||
private static final Object LOCK = new Object();
|
||||
private static volatile DownloadSchedulers INSTANCE = null;
|
||||
/**
|
||||
* 下载失败次数
|
||||
*/
|
||||
int mFailNum = 10;
|
||||
|
||||
/**
|
||||
* 超时时间
|
||||
*/
|
||||
long mTimeOut = 10000;
|
||||
|
||||
/**
|
||||
* 下载器任务监听
|
||||
*/
|
||||
Map<String, OnSchedulerListener> mSchedulerListeners = new ConcurrentHashMap<>();
|
||||
ITaskQueue mQueue;
|
||||
|
||||
public DownloadSchedulers(ITaskQueue downloadTaskQueue) {
|
||||
mQueue = downloadTaskQueue;
|
||||
}
|
||||
|
||||
public static DownloadSchedulers getInstance(DownloadTaskQueue queue) {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new DownloadSchedulers(queue);
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
@Override public boolean handleMessage(Message msg) {
|
||||
Task task = (Task) msg.obj;
|
||||
if (task == null) {
|
||||
Log.e(TAG, "请传入下载任务");
|
||||
return true;
|
||||
}
|
||||
callback(msg.what, task);
|
||||
DownloadEntity entity = task.getDownloadEntity();
|
||||
switch (msg.what) {
|
||||
case STOP:
|
||||
case CANCEL:
|
||||
mQueue.removeTask(entity);
|
||||
if (mQueue.size() != ExecutePool.mSize) {
|
||||
startNextTask(entity);
|
||||
}
|
||||
break;
|
||||
case COMPLETE:
|
||||
startNextTask(entity);
|
||||
break;
|
||||
case FAIL:
|
||||
handleFailTask(entity);
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 回调
|
||||
*
|
||||
* @param state 状态
|
||||
*/
|
||||
private void callback(int state, Task task) {
|
||||
if (mSchedulerListeners.size() > 0) {
|
||||
if (!TextUtils.isEmpty(task.getTargetName())) {
|
||||
callback(state, task, mSchedulerListeners.get(task.getTargetName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void callback(int state, Task task, OnSchedulerListener listener) {
|
||||
if (listener != null) {
|
||||
//Task task = mQueue.getTask(entity);
|
||||
if (task == null) {
|
||||
//Log.e(TAG, "队列中没有下载链接【" + entity.getDownloadUrl() + "】的任务");
|
||||
Log.e(TAG, "传递的下载任务");
|
||||
return;
|
||||
}
|
||||
switch (state) {
|
||||
case RUNNING:
|
||||
listener.onTaskRunning(task);
|
||||
break;
|
||||
case START:
|
||||
listener.onTaskStart(task);
|
||||
break;
|
||||
case STOP:
|
||||
listener.onTaskStop(task);
|
||||
break;
|
||||
case RESUME:
|
||||
listener.onTaskResume(task);
|
||||
break;
|
||||
case PRE:
|
||||
listener.onTaskPre(task);
|
||||
break;
|
||||
case CANCEL:
|
||||
listener.onTaskCancel(task);
|
||||
break;
|
||||
case COMPLETE:
|
||||
listener.onTaskComplete(task);
|
||||
break;
|
||||
case FAIL:
|
||||
listener.onTaskFail(task);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理下载任务下载失败的情形
|
||||
*
|
||||
* @param entity 失败实体
|
||||
*/
|
||||
@Override public void handleFailTask(DownloadEntity entity) {
|
||||
if (entity.getFailNum() <= mFailNum) {
|
||||
Task task = mQueue.getTask(entity);
|
||||
mQueue.reTryStart(task);
|
||||
try {
|
||||
Thread.currentThread().sleep(4000);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
} else {
|
||||
startNextTask(entity);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动下一个任务,条件:任务停止,取消下载,任务完成
|
||||
*
|
||||
* @param entity 通过Handler传递的下载实体
|
||||
*/
|
||||
@Override public void startNextTask(DownloadEntity entity) {
|
||||
mQueue.removeTask(entity);
|
||||
Task newTask = mQueue.getNextTask();
|
||||
if (newTask == null) {
|
||||
Log.w(TAG, "没有下一任务");
|
||||
return;
|
||||
}
|
||||
if (newTask.getDownloadEntity().getState() == DownloadEntity.STATE_WAIT) {
|
||||
mQueue.startTask(newTask);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void addSchedulerListener(Object target, OnSchedulerListener schedulerListener) {
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("target 不能为null");
|
||||
}
|
||||
String name = target.getClass().getName();
|
||||
if (mSchedulerListeners.get(name) != null) {
|
||||
Log.w(TAG, "监听器已存在");
|
||||
return;
|
||||
}
|
||||
mSchedulerListeners.put(name, schedulerListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSchedulerListener(Object target, OnSchedulerListener schedulerListener) {
|
||||
if (target == null) {
|
||||
throw new IllegalArgumentException("target 不能为null");
|
||||
}
|
||||
mSchedulerListeners.remove(target.getClass().getName());
|
||||
}
|
||||
|
||||
public void setFailNum(int mFailNum) {
|
||||
this.mFailNum = mFailNum;
|
||||
}
|
||||
|
||||
public void setTimeOut(long timeOut) {
|
||||
this.mTimeOut = timeOut;
|
||||
}
|
||||
}
|
@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.arialyy.aria.core.scheduler;
|
||||
|
||||
import android.os.Handler;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2016/11/2.
|
||||
* 下载调度器接口
|
||||
*/
|
||||
public interface IDownloadSchedulers extends Handler.Callback {
|
||||
|
||||
/**
|
||||
* 注册下载器监听,一个观察者只能注册一次监听
|
||||
*
|
||||
* @param target 观察者,创建该监听器的对象
|
||||
* @param schedulerListener {@link OnSchedulerListener}
|
||||
*/
|
||||
public void addSchedulerListener(Object target, OnSchedulerListener schedulerListener);
|
||||
|
||||
/**
|
||||
* @param target 观察者,创建该监听器的对象
|
||||
* 取消注册监听器
|
||||
*/
|
||||
public void removeSchedulerListener(Object target, OnSchedulerListener schedulerListener);
|
||||
|
||||
/**
|
||||
* 处理下载任务下载失败的情形
|
||||
*
|
||||
* @param entity 下载实体
|
||||
*/
|
||||
public void handleFailTask(DownloadEntity entity);
|
||||
|
||||
/**
|
||||
* 启动下一个任务,条件:任务停止,取消下载,任务完成
|
||||
*
|
||||
* @param entity 通过Handler传递的下载实体
|
||||
*/
|
||||
public void startNextTask(DownloadEntity entity);
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
package com.arialyy.aria.core.scheduler;
|
||||
|
||||
import com.arialyy.aria.core.task.Task;
|
||||
|
||||
/**
|
||||
* Target处理任务监听
|
||||
*/
|
||||
public interface OnSchedulerListener {
|
||||
/**
|
||||
* 任务预加载
|
||||
*/
|
||||
public void onTaskPre(Task task);
|
||||
|
||||
/**
|
||||
* 任务恢复下载
|
||||
*/
|
||||
public void onTaskResume(Task task);
|
||||
|
||||
/**
|
||||
* 任务开始
|
||||
*/
|
||||
public void onTaskStart(Task task);
|
||||
|
||||
/**
|
||||
* 任务停止
|
||||
*/
|
||||
public void onTaskStop(Task task);
|
||||
|
||||
/**
|
||||
* 任务取消
|
||||
*/
|
||||
public void onTaskCancel(Task task);
|
||||
|
||||
/**
|
||||
* 任务下载失败
|
||||
*/
|
||||
public void onTaskFail(Task task);
|
||||
|
||||
/**
|
||||
* 任务完成
|
||||
*/
|
||||
public void onTaskComplete(Task task);
|
||||
|
||||
/**
|
||||
* 任务执行中
|
||||
*/
|
||||
public void onTaskRunning(Task task);
|
||||
}
|
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.task;
|
||||
|
||||
class DownloadListener implements IDownloadListener {
|
||||
|
||||
@Override public void onResume(long resumeLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onCancel() {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onFail() {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onPre() {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onPostPre(long fileSize) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onProgress(long currentLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onChildComplete(long finishLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onStart(long startLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onChildResume(long resumeLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onStop(long stopLocation) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onComplete() {
|
||||
|
||||
}
|
||||
}
|
535
Aria/src/main/java/com/arialyy/aria/core/task/DownloadUtil.java
Normal file
535
Aria/src/main/java/com/arialyy/aria/core/task/DownloadUtil.java
Normal file
@ -0,0 +1,535 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.task;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.ProtocolException;
|
||||
import java.net.URL;
|
||||
import java.util.Properties;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/8/25.
|
||||
* 下载工具类
|
||||
*/
|
||||
final class DownloadUtil implements IDownloadUtil {
|
||||
private static final String TAG = "DownloadUtil";
|
||||
private static final Object LOCK = new Object();
|
||||
/**
|
||||
* 线程数
|
||||
*/
|
||||
private final int THREAD_NUM;
|
||||
//下载监听
|
||||
private IDownloadListener mListener;
|
||||
private int mConnectTimeOut = 5000 * 4; //连接超时时间
|
||||
private int mReadTimeOut = 5000 * 20; //流读取的超时时间
|
||||
/**
|
||||
* 已经完成下载任务的线程数量
|
||||
*/
|
||||
private int mCompleteThreadNum = 0;
|
||||
private boolean isDownloading = false;
|
||||
private boolean isStop = false;
|
||||
private boolean isCancel = false;
|
||||
private boolean isNewTask = true;
|
||||
private int mCancelNum = 0;
|
||||
private long mCurrentLocation = 0;
|
||||
private int mStopNum = 0;
|
||||
private Context mContext;
|
||||
private DownloadEntity mDownloadEntity;
|
||||
private ExecutorService mFixedThreadPool;
|
||||
private SparseArray<Runnable> mTask = new SparseArray<>();
|
||||
|
||||
DownloadUtil(Context context, DownloadEntity entity, IDownloadListener downloadListener) {
|
||||
this(context, entity, downloadListener, 3);
|
||||
}
|
||||
|
||||
DownloadUtil(Context context, DownloadEntity entity, IDownloadListener downloadListener,
|
||||
int threadNum) {
|
||||
mContext = context.getApplicationContext();
|
||||
mDownloadEntity = entity;
|
||||
mListener = downloadListener;
|
||||
THREAD_NUM = threadNum;
|
||||
mFixedThreadPool = Executors.newFixedThreadPool(THREAD_NUM);
|
||||
}
|
||||
|
||||
public IDownloadListener getListener() {
|
||||
return mListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置连接超时时间
|
||||
*/
|
||||
public void setConnectTimeOut(int timeOut) {
|
||||
mConnectTimeOut = timeOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置流读取的超时时间
|
||||
*/
|
||||
public void setReadTimeOut(int readTimeOut) {
|
||||
mReadTimeOut = readTimeOut;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前下载位置
|
||||
*/
|
||||
@Override public long getCurrentLocation() {
|
||||
return mCurrentLocation;
|
||||
}
|
||||
|
||||
@Override public boolean isDownloading() {
|
||||
return isDownloading;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
@Override public void cancelDownload() {
|
||||
isCancel = true;
|
||||
isDownloading = false;
|
||||
mFixedThreadPool.shutdown();
|
||||
for (int i = 0; i < THREAD_NUM; i++) {
|
||||
DownLoadTask task = (DownLoadTask) mTask.get(i);
|
||||
if (task != null) {
|
||||
task.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止下载
|
||||
*/
|
||||
@Override public void stopDownload() {
|
||||
isStop = true;
|
||||
isDownloading = false;
|
||||
mFixedThreadPool.shutdown();
|
||||
for (int i = 0; i < THREAD_NUM; i++) {
|
||||
DownLoadTask task = (DownLoadTask) 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() {
|
||||
isDownloading = true;
|
||||
mCurrentLocation = 0;
|
||||
isStop = false;
|
||||
isCancel = false;
|
||||
mCancelNum = 0;
|
||||
mStopNum = 0;
|
||||
final String filePath = mDownloadEntity.getDownloadPath();
|
||||
final String downloadUrl = mDownloadEntity.getDownloadUrl();
|
||||
final File dFile = new File(filePath);
|
||||
//读取已完成的线程数
|
||||
final File configFile =
|
||||
new File(mContext.getFilesDir().getPath() + "/temp/" + dFile.getName() + ".properties");
|
||||
try {
|
||||
if (!configFile.exists()) { //记录文件被删除,则重新下载
|
||||
isNewTask = true;
|
||||
CommonUtil.createFile(configFile.getPath());
|
||||
} else {
|
||||
isNewTask = !dFile.exists();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
failDownload("下载失败,记录文件被删除");
|
||||
return;
|
||||
}
|
||||
mListener.onPre();
|
||||
new Thread(new Runnable() {
|
||||
@Override public void run() {
|
||||
try {
|
||||
URL url = new URL(downloadUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
setConnectParam(conn);
|
||||
conn.setConnectTimeout(mConnectTimeOut * 4);
|
||||
conn.connect();
|
||||
int len = conn.getContentLength();
|
||||
if (len < 0) { //网络被劫持时会出现这个问题
|
||||
failDownload("下载失败,网络被劫持");
|
||||
return;
|
||||
}
|
||||
int code = conn.getResponseCode();
|
||||
if (code == 200) {
|
||||
int fileLength = conn.getContentLength();
|
||||
//必须建一个文件
|
||||
CommonUtil.createFile(filePath);
|
||||
RandomAccessFile file = new RandomAccessFile(filePath, "rwd");
|
||||
//设置文件长度
|
||||
file.setLength(fileLength);
|
||||
mListener.onPostPre(fileLength);
|
||||
//分配每条线程的下载区间
|
||||
Properties pro = null;
|
||||
pro = CommonUtil.loadConfig(configFile);
|
||||
if (pro.isEmpty()) {
|
||||
isNewTask = true;
|
||||
} else {
|
||||
for (int i = 0; i < THREAD_NUM; i++) {
|
||||
if (pro.getProperty(dFile.getName() + "_record_" + i) == null) {
|
||||
Object state = pro.getProperty(dFile.getName() + "_state_" + i);
|
||||
if (state != null && Integer.parseInt(state + "") == 1) {
|
||||
continue;
|
||||
}
|
||||
isNewTask = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
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(dFile.getName() + "_state_" + i);
|
||||
if (state != null && Integer.parseInt(state + "") == 1) { //该线程已经完成
|
||||
mCurrentLocation += endL - startL;
|
||||
Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++");
|
||||
mCompleteThreadNum++;
|
||||
mStopNum++;
|
||||
mCancelNum++;
|
||||
if (mCompleteThreadNum == THREAD_NUM) {
|
||||
if (configFile.exists()) {
|
||||
configFile.delete();
|
||||
}
|
||||
mListener.onComplete();
|
||||
isDownloading = false;
|
||||
return;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
//分配下载位置
|
||||
Object record = pro.getProperty(dFile.getName() + "_record_" + i);
|
||||
if (!isNewTask
|
||||
&& record != null
|
||||
&& Long.parseLong(record + "") > 0) { //如果有记录,则恢复下载
|
||||
Long r = Long.parseLong(record + "");
|
||||
mCurrentLocation += r - startL;
|
||||
Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++");
|
||||
mListener.onChildResume(r);
|
||||
startL = r;
|
||||
recordL[rl] = i;
|
||||
rl++;
|
||||
} else {
|
||||
isNewTask = true;
|
||||
}
|
||||
if (isNewTask) {
|
||||
recordL[rl] = i;
|
||||
rl++;
|
||||
}
|
||||
if (i == (THREAD_NUM - 1)) {
|
||||
//如果整个文件的大小不为线程个数的整数倍,则最后一个线程的结束位置即为文件的总长度
|
||||
endL = fileLength;
|
||||
}
|
||||
ConfigEntity entity =
|
||||
new ConfigEntity(mContext, fileLength, downloadUrl, dFile, i, startL, endL);
|
||||
DownLoadTask task = new DownLoadTask(entity);
|
||||
mTask.put(i, task);
|
||||
}
|
||||
if (mCurrentLocation > 0) {
|
||||
mListener.onResume(mCurrentLocation);
|
||||
} else {
|
||||
mListener.onStart(mCurrentLocation);
|
||||
}
|
||||
for (int l : recordL) {
|
||||
if (l == -1) continue;
|
||||
Runnable task = mTask.get(l);
|
||||
if (task != null) {
|
||||
mFixedThreadPool.execute(task);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
failDownload("下载失败,返回码:" + code);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
failDownload("下载失败【downloadUrl:"
|
||||
+ downloadUrl
|
||||
+ "】\n【filePath:"
|
||||
+ filePath
|
||||
+ "】"
|
||||
+ CommonUtil.getPrintException(e));
|
||||
}
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
@Override public void resumeDownload() {
|
||||
startDownload();
|
||||
}
|
||||
|
||||
private void failDownload(String msg) {
|
||||
Log.e(TAG, msg);
|
||||
isDownloading = false;
|
||||
stopDownload();
|
||||
mListener.onFail();
|
||||
}
|
||||
|
||||
private void setConnectParam(HttpURLConnection conn) throws ProtocolException {
|
||||
conn.setRequestMethod("GET");
|
||||
conn.setRequestProperty("Charset", "UTF-8");
|
||||
conn.setRequestProperty("User-Agent",
|
||||
"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)");
|
||||
conn.setRequestProperty("Accept",
|
||||
"image/gif, image/jpeg, image/pjpeg, image/pjpeg, application/x-shockwave-flash, application/xaml+xml, application/vnd.ms-xpsdocument, application/x-ms-xbap, application/x-ms-application, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*");
|
||||
}
|
||||
|
||||
/**
|
||||
* 子线程下载信息类
|
||||
*/
|
||||
private static class ConfigEntity {
|
||||
//文件大小
|
||||
long fileSize;
|
||||
String downloadUrl;
|
||||
int threadId;
|
||||
long startLocation;
|
||||
long endLocation;
|
||||
File tempFile;
|
||||
Context context;
|
||||
|
||||
private ConfigEntity(Context context, long fileSize, String downloadUrl, File file,
|
||||
int threadId, long startLocation, long endLocation) {
|
||||
this.fileSize = fileSize;
|
||||
this.downloadUrl = downloadUrl;
|
||||
this.tempFile = file;
|
||||
this.threadId = threadId;
|
||||
this.startLocation = startLocation;
|
||||
this.endLocation = endLocation;
|
||||
this.context = context;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单个线程的下载任务
|
||||
*/
|
||||
private class DownLoadTask implements Runnable {
|
||||
private static final String TAG = "DownLoadTask";
|
||||
private ConfigEntity dEntity;
|
||||
private String configFPath;
|
||||
private long currentLocation = 0;
|
||||
|
||||
private DownLoadTask(ConfigEntity downloadInfo) {
|
||||
this.dEntity = downloadInfo;
|
||||
configFPath = dEntity.context.getFilesDir().getPath()
|
||||
+ "/temp/"
|
||||
+ dEntity.tempFile.getName()
|
||||
+ ".properties";
|
||||
}
|
||||
|
||||
@Override public void run() {
|
||||
HttpURLConnection conn = null;
|
||||
InputStream is = null;
|
||||
try {
|
||||
Log.d(TAG, "线程_"
|
||||
+ dEntity.threadId
|
||||
+ "_正在下载【开始位置 : "
|
||||
+ dEntity.startLocation
|
||||
+ ",结束位置:"
|
||||
+ dEntity.endLocation
|
||||
+ "】");
|
||||
URL url = new URL(dEntity.downloadUrl);
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
//在头里面请求下载开始位置和结束位置
|
||||
conn.setRequestProperty("Range",
|
||||
"bytes=" + dEntity.startLocation + "-" + dEntity.endLocation);
|
||||
setConnectParam(conn);
|
||||
conn.setConnectTimeout(mConnectTimeOut);
|
||||
conn.setReadTimeout(mReadTimeOut); //设置读取流的等待时间,必须设置该参数
|
||||
is = conn.getInputStream();
|
||||
//创建可设置位置的文件
|
||||
RandomAccessFile file = new RandomAccessFile(dEntity.tempFile, "rwd");
|
||||
//设置每条线程写入文件的位置
|
||||
file.seek(dEntity.startLocation);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
//当前子线程的下载位置
|
||||
currentLocation = dEntity.startLocation;
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
if (isCancel) {
|
||||
Log.d(TAG, "++++++++++ thread_" + dEntity.threadId + "_cancel ++++++++++");
|
||||
break;
|
||||
}
|
||||
if (isStop) {
|
||||
break;
|
||||
}
|
||||
//把下载数据数据写入文件
|
||||
file.write(buffer, 0, len);
|
||||
progress(len);
|
||||
currentLocation += len;
|
||||
}
|
||||
file.close();
|
||||
//close 为阻塞的,需要使用线程池来处理
|
||||
is.close();
|
||||
conn.disconnect();
|
||||
|
||||
if (isCancel) {
|
||||
cancel();
|
||||
return;
|
||||
}
|
||||
//停止状态不需要删除记录文件
|
||||
if (isStop) {
|
||||
//stop();
|
||||
return;
|
||||
}
|
||||
Log.i(TAG, "线程【" + dEntity.threadId + "】下载完毕");
|
||||
writeConfig(dEntity.tempFile.getName() + "_state_" + dEntity.threadId, 1 + "");
|
||||
mListener.onChildComplete(dEntity.endLocation);
|
||||
mCompleteThreadNum++;
|
||||
if (mCompleteThreadNum == THREAD_NUM) {
|
||||
File configFile = new File(configFPath);
|
||||
if (configFile.exists()) {
|
||||
configFile.delete();
|
||||
}
|
||||
isDownloading = false;
|
||||
mListener.onComplete();
|
||||
}
|
||||
} catch (MalformedURLException e) {
|
||||
failDownload(dEntity, currentLocation, "下载链接异常", e);
|
||||
} catch (IOException e) {
|
||||
failDownload(dEntity, currentLocation, "下载失败【" + dEntity.downloadUrl + "】", e);
|
||||
} catch (Exception e) {
|
||||
failDownload(dEntity, currentLocation, "获取流失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止下载
|
||||
*/
|
||||
protected void stop() {
|
||||
synchronized (LOCK) {
|
||||
try {
|
||||
mStopNum++;
|
||||
String location = String.valueOf(currentLocation);
|
||||
Log.i(TAG, "thread_" + dEntity.threadId + "_stop, stop location ==> " + currentLocation);
|
||||
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
|
||||
if (mStopNum == THREAD_NUM) {
|
||||
Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++");
|
||||
isDownloading = false;
|
||||
mListener.onStop(mCurrentLocation);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
private void cancel() {
|
||||
synchronized (LOCK) {
|
||||
mCancelNum++;
|
||||
if (mCancelNum == THREAD_NUM) {
|
||||
File configFile = new File(configFPath);
|
||||
if (configFile.exists()) {
|
||||
configFile.delete();
|
||||
}
|
||||
if (dEntity.tempFile.exists()) {
|
||||
dEntity.tempFile.delete();
|
||||
}
|
||||
Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++");
|
||||
isDownloading = false;
|
||||
mListener.onCancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void progress(long len) {
|
||||
synchronized (LOCK) {
|
||||
mCurrentLocation += len;
|
||||
mListener.onProgress(mCurrentLocation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 将记录写入到配置文件
|
||||
*/
|
||||
private void writeConfig(String key, String record) throws IOException {
|
||||
File configFile = new File(configFPath);
|
||||
Properties pro = CommonUtil.loadConfig(configFile);
|
||||
pro.setProperty(key, record);
|
||||
CommonUtil.saveConfig(configFile, pro);
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载失败
|
||||
*/
|
||||
private void failDownload(ConfigEntity dEntity, long currentLocation, String msg,
|
||||
Exception ex) {
|
||||
synchronized (LOCK) {
|
||||
try {
|
||||
isDownloading = false;
|
||||
isStop = true;
|
||||
Log.e(TAG, msg);
|
||||
if (ex != null) {
|
||||
Log.e(TAG, CommonUtil.getPrintException(ex));
|
||||
}
|
||||
if (currentLocation != -1) {
|
||||
String location = String.valueOf(currentLocation);
|
||||
writeConfig(dEntity.tempFile.getName() + "_record_" + dEntity.threadId, location);
|
||||
}
|
||||
mListener.onFail();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.task;
|
||||
|
||||
/**
|
||||
* 下载监听
|
||||
*/
|
||||
public interface IDownloadListener {
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
public void onCancel();
|
||||
|
||||
/**
|
||||
* 下载失败
|
||||
*/
|
||||
public void onFail();
|
||||
|
||||
/**
|
||||
* 预处理
|
||||
*/
|
||||
public void onPre();
|
||||
|
||||
/**
|
||||
* 预处理完成,准备下载---开始下载之间
|
||||
*/
|
||||
public void onPostPre(long fileSize);
|
||||
|
||||
/**
|
||||
* 下载监听
|
||||
*/
|
||||
public void onProgress(long currentLocation);
|
||||
|
||||
/**
|
||||
* 单一线程的结束位置
|
||||
*/
|
||||
public void onChildComplete(long finishLocation);
|
||||
|
||||
/**
|
||||
* 开始
|
||||
*/
|
||||
public void onStart(long startLocation);
|
||||
|
||||
/**
|
||||
* 子程恢复下载的位置
|
||||
*/
|
||||
public void onChildResume(long resumeLocation);
|
||||
|
||||
/**
|
||||
* 恢复位置
|
||||
*/
|
||||
public void onResume(long resumeLocation);
|
||||
|
||||
/**
|
||||
* 停止
|
||||
*/
|
||||
public void onStop(long stopLocation);
|
||||
|
||||
/**
|
||||
* 下载完成
|
||||
*/
|
||||
public void onComplete();
|
||||
}
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.task;
|
||||
|
||||
/**
|
||||
* Created by “AriaLyy@outlook.com” on 2016/10/31.
|
||||
* 抽象的下载接口
|
||||
*/
|
||||
public interface IDownloadUtil {
|
||||
|
||||
/**
|
||||
* 获取当前下载位置
|
||||
*/
|
||||
public long getCurrentLocation();
|
||||
|
||||
/**
|
||||
* 是否正在下载
|
||||
*
|
||||
* @return true, 正在下载
|
||||
*/
|
||||
public boolean isDownloading();
|
||||
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
public void cancelDownload();
|
||||
|
||||
/**
|
||||
* 停止下载
|
||||
*/
|
||||
public void stopDownload();
|
||||
|
||||
/**
|
||||
* 开始下载
|
||||
*/
|
||||
public void startDownload();
|
||||
|
||||
/**
|
||||
* 从上次断点恢复下载
|
||||
*/
|
||||
public void resumeDownload();
|
||||
|
||||
/**
|
||||
* 删除下载记录文件
|
||||
*/
|
||||
public void delConfigFile();
|
||||
|
||||
/**
|
||||
* 删除temp文件
|
||||
*/
|
||||
public void delTempFile();
|
||||
}
|
331
Aria/src/main/java/com/arialyy/aria/core/task/Task.java
Normal file
331
Aria/src/main/java/com/arialyy/aria/core/task/Task.java
Normal file
@ -0,0 +1,331 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.task;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Handler;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.DownloadManager;
|
||||
import com.arialyy.aria.core.scheduler.DownloadSchedulers;
|
||||
import com.arialyy.aria.core.scheduler.IDownloadSchedulers;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/11.
|
||||
* 下载任务类
|
||||
*/
|
||||
public class Task {
|
||||
public static final String TAG = "Task";
|
||||
/**
|
||||
* 产生该任务对象的hash码
|
||||
*/
|
||||
private String mTargetName;
|
||||
private DownloadEntity mEntity;
|
||||
private IDownloadListener mListener;
|
||||
private Handler mOutHandler;
|
||||
private Context mContext;
|
||||
private IDownloadUtil mUtil;
|
||||
|
||||
private Task(Context context, DownloadEntity entity) {
|
||||
mContext = context.getApplicationContext();
|
||||
mEntity = entity;
|
||||
init();
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mListener = new DListener(mContext, mEntity, mOutHandler);
|
||||
mUtil = new DownloadUtil(mContext, mEntity, mListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* 开始下载
|
||||
*/
|
||||
public void start() {
|
||||
if (mUtil.isDownloading()) {
|
||||
Log.d(TAG, "任务正在下载");
|
||||
} else {
|
||||
if (mListener == null) {
|
||||
mListener = new DListener(mContext, mEntity, mOutHandler);
|
||||
}
|
||||
mUtil.startDownload();
|
||||
}
|
||||
}
|
||||
|
||||
public DownloadEntity getDownloadEntity() {
|
||||
return mEntity;
|
||||
}
|
||||
|
||||
public String getTargetName() {
|
||||
return mTargetName;
|
||||
}
|
||||
|
||||
public void setmTargetName(String targetName) {
|
||||
this.mTargetName = targetName;
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止下载
|
||||
*/
|
||||
public void stop() {
|
||||
if (mUtil.isDownloading()) {
|
||||
mUtil.stopDownload();
|
||||
} else {
|
||||
mEntity.setState(DownloadEntity.STATE_STOP);
|
||||
mEntity.save();
|
||||
sendInState2Target(DownloadSchedulers.STOP);
|
||||
|
||||
// 发送停止下载的广播
|
||||
Intent intent = createIntent(DownloadManager.ACTION_STOP);
|
||||
intent.putExtra(DownloadManager.CURRENT_LOCATION, mEntity.getCurrentProgress());
|
||||
intent.putExtra(DownloadManager.ENTITY, mEntity);
|
||||
mContext.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载工具
|
||||
*/
|
||||
public IDownloadUtil getDownloadUtil() {
|
||||
return mUtil;
|
||||
}
|
||||
|
||||
/**
|
||||
* 任务下载状态
|
||||
*/
|
||||
public boolean isDownloading() {
|
||||
return mUtil.isDownloading();
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消下载
|
||||
*/
|
||||
public void cancel() {
|
||||
if (mUtil.isDownloading()) {
|
||||
mUtil.cancelDownload();
|
||||
} else {
|
||||
// 如果任务不是下载状态
|
||||
mUtil.cancelDownload();
|
||||
mUtil.delConfigFile();
|
||||
mUtil.delTempFile();
|
||||
mEntity.deleteData();
|
||||
sendInState2Target(DownloadSchedulers.CANCEL);
|
||||
|
||||
//发送取消下载的广播
|
||||
Intent intent = createIntent(DownloadManager.ACTION_CANCEL);
|
||||
intent.putExtra(DownloadManager.ENTITY, mEntity);
|
||||
mContext.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建特定的Intent
|
||||
*/
|
||||
private Intent createIntent(String action) {
|
||||
Uri.Builder builder = new Uri.Builder();
|
||||
builder.scheme(mContext.getPackageName());
|
||||
Uri uri = builder.build();
|
||||
Intent intent = new Intent(action);
|
||||
intent.setData(uri);
|
||||
return intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将任务状态发送给下载器
|
||||
*
|
||||
* @param state {@link DownloadSchedulers#START}
|
||||
*/
|
||||
private void sendInState2Target(int state) {
|
||||
if (mOutHandler != null) {
|
||||
mOutHandler.obtainMessage(state, this).sendToTarget();
|
||||
}
|
||||
}
|
||||
|
||||
static class Builder {
|
||||
DownloadEntity downloadEntity;
|
||||
Handler outHandler;
|
||||
Context context;
|
||||
int threadNum = 3;
|
||||
String targetName;
|
||||
IDownloadUtil downloadUtil;
|
||||
|
||||
public Builder(Context context, DownloadEntity downloadEntity) {
|
||||
this("", context, downloadEntity);
|
||||
}
|
||||
|
||||
public Builder(String targetName, Context context, DownloadEntity downloadEntity) {
|
||||
this.targetName = targetName;
|
||||
this.context = context;
|
||||
this.downloadEntity = downloadEntity;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置自定义Handler处理下载状态时间
|
||||
*
|
||||
* @param schedulers {@link IDownloadSchedulers}
|
||||
*/
|
||||
public Builder setOutHandler(IDownloadSchedulers schedulers) {
|
||||
this.outHandler = new Handler(schedulers);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置线程数
|
||||
*/
|
||||
public Builder setThreadNum(int threadNum) {
|
||||
this.threadNum = threadNum;
|
||||
return this;
|
||||
}
|
||||
|
||||
///**
|
||||
// * 设置自定义下载工具
|
||||
// *
|
||||
// * @param downloadUtil {@link IDownloadUtil}
|
||||
// */
|
||||
//public Builder setDownloadUtil(IDownloadUtil downloadUtil) {
|
||||
// this.downloadUtil = downloadUtil;
|
||||
// return this;
|
||||
//}
|
||||
|
||||
public Task build() {
|
||||
Task task = new Task(context, downloadEntity);
|
||||
task.mOutHandler = outHandler;
|
||||
task.setmTargetName(targetName);
|
||||
downloadEntity.save();
|
||||
return task;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载监听类
|
||||
*/
|
||||
private class DListener extends DownloadListener {
|
||||
Handler outHandler;
|
||||
Context context;
|
||||
Intent sendIntent;
|
||||
long INTERVAL = 1024 * 10; //10k大小的间隔
|
||||
long lastLen = 0; //上一次发送长度
|
||||
long lastTime = 0;
|
||||
long INTERVAL_TIME = 1000; //1m更新周期
|
||||
boolean isFirst = true;
|
||||
DownloadEntity downloadEntity;
|
||||
|
||||
DListener(Context context, DownloadEntity downloadEntity, Handler outHandler) {
|
||||
this.context = context;
|
||||
this.outHandler = outHandler;
|
||||
this.downloadEntity = downloadEntity;
|
||||
sendIntent = createIntent(DownloadManager.ACTION_RUNNING);
|
||||
sendIntent.putExtra(DownloadManager.ENTITY, downloadEntity);
|
||||
}
|
||||
|
||||
@Override public void onPre() {
|
||||
super.onPre();
|
||||
downloadEntity.setState(DownloadEntity.STATE_PRE);
|
||||
sendIntent(DownloadManager.ACTION_PRE, -1);
|
||||
}
|
||||
|
||||
@Override public void onPostPre(long fileSize) {
|
||||
super.onPostPre(fileSize);
|
||||
downloadEntity.setFileSize(fileSize);
|
||||
downloadEntity.setState(DownloadEntity.STATE_POST_PRE);
|
||||
sendInState2Target(DownloadSchedulers.PRE);
|
||||
sendIntent(DownloadManager.ACTION_POST_PRE, -1);
|
||||
}
|
||||
|
||||
@Override public void onResume(long resumeLocation) {
|
||||
super.onResume(resumeLocation);
|
||||
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
|
||||
sendInState2Target(DownloadSchedulers.RESUME);
|
||||
sendIntent(DownloadManager.ACTION_RESUME, resumeLocation);
|
||||
}
|
||||
|
||||
@Override public void onStart(long startLocation) {
|
||||
super.onStart(startLocation);
|
||||
downloadEntity.setState(DownloadEntity.STATE_DOWNLOAD_ING);
|
||||
downloadEntity.setFailNum(0);
|
||||
sendInState2Target(DownloadSchedulers.START);
|
||||
sendIntent(DownloadManager.ACTION_START, startLocation);
|
||||
}
|
||||
|
||||
@Override public void onProgress(long currentLocation) {
|
||||
super.onProgress(currentLocation);
|
||||
if (System.currentTimeMillis() - lastTime > INTERVAL_TIME) {
|
||||
long speed = currentLocation - lastLen;
|
||||
sendIntent.putExtra(DownloadManager.CURRENT_LOCATION, currentLocation);
|
||||
sendIntent.putExtra(DownloadManager.CURRENT_SPEED, speed);
|
||||
lastTime = System.currentTimeMillis();
|
||||
if (isFirst) {
|
||||
downloadEntity.setSpeed(0);
|
||||
isFirst = false;
|
||||
} else {
|
||||
downloadEntity.setSpeed(speed);
|
||||
}
|
||||
downloadEntity.setCurrentProgress(currentLocation);
|
||||
lastLen = currentLocation;
|
||||
sendInState2Target(DownloadSchedulers.RUNNING);
|
||||
context.sendBroadcast(sendIntent);
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void onStop(long stopLocation) {
|
||||
super.onStop(stopLocation);
|
||||
downloadEntity.setState(DownloadEntity.STATE_STOP);
|
||||
downloadEntity.setSpeed(0);
|
||||
sendInState2Target(DownloadSchedulers.STOP);
|
||||
sendIntent(DownloadManager.ACTION_STOP, stopLocation);
|
||||
}
|
||||
|
||||
@Override public void onCancel() {
|
||||
super.onCancel();
|
||||
downloadEntity.setState(DownloadEntity.STATE_CANCEL);
|
||||
sendInState2Target(DownloadSchedulers.CANCEL);
|
||||
sendIntent(DownloadManager.ACTION_CANCEL, -1);
|
||||
downloadEntity.deleteData();
|
||||
}
|
||||
|
||||
@Override public void onComplete() {
|
||||
super.onComplete();
|
||||
downloadEntity.setState(DownloadEntity.STATE_COMPLETE);
|
||||
downloadEntity.setDownloadComplete(true);
|
||||
downloadEntity.setSpeed(0);
|
||||
sendInState2Target(DownloadSchedulers.COMPLETE);
|
||||
sendIntent(DownloadManager.ACTION_COMPLETE, downloadEntity.getFileSize());
|
||||
}
|
||||
|
||||
@Override public void onFail() {
|
||||
super.onFail();
|
||||
downloadEntity.setFailNum(downloadEntity.getFailNum() + 1);
|
||||
downloadEntity.setState(DownloadEntity.STATE_FAIL);
|
||||
downloadEntity.setSpeed(0);
|
||||
sendInState2Target(DownloadSchedulers.FAIL);
|
||||
sendIntent(DownloadManager.ACTION_FAIL, -1);
|
||||
}
|
||||
|
||||
private void sendIntent(String action, long location) {
|
||||
downloadEntity.setDownloadComplete(action.equals(DownloadManager.ACTION_COMPLETE));
|
||||
downloadEntity.setCurrentProgress(location);
|
||||
downloadEntity.update();
|
||||
Intent intent = createIntent(action);
|
||||
intent.putExtra(DownloadManager.ENTITY, downloadEntity);
|
||||
if (location != -1) {
|
||||
intent.putExtra(DownloadManager.CURRENT_LOCATION, location);
|
||||
}
|
||||
//context.sendBroadcast(intent);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.task;
|
||||
|
||||
import android.content.Context;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.scheduler.IDownloadSchedulers;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/8/18.
|
||||
* 任务工厂
|
||||
*/
|
||||
public class TaskFactory {
|
||||
private static final String TAG = "TaskFactory";
|
||||
|
||||
private static final Object LOCK = new Object();
|
||||
private static volatile TaskFactory INSTANCE = null;
|
||||
|
||||
private TaskFactory() {
|
||||
|
||||
}
|
||||
|
||||
public static TaskFactory getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
synchronized (LOCK) {
|
||||
INSTANCE = new TaskFactory();
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建普通下载任务
|
||||
*
|
||||
* @param entity 下载实体
|
||||
* @param schedulers {@link IDownloadSchedulers}
|
||||
*/
|
||||
public Task createTask(Context context, DownloadEntity entity, IDownloadSchedulers schedulers) {
|
||||
return createTask("", context, entity, schedulers);
|
||||
}
|
||||
|
||||
public Task createTask(String targetName, Context context, DownloadEntity entity,
|
||||
IDownloadSchedulers schedulers) {
|
||||
Task.Builder builder = new Task.Builder(targetName, context, entity);
|
||||
builder.setOutHandler(schedulers);
|
||||
return builder.build();
|
||||
}
|
||||
}
|
158
Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java
Normal file
158
Aria/src/main/java/com/arialyy/aria/orm/DbEntity.java
Normal file
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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 android.support.annotation.NonNull;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/11/2.
|
||||
* 所有数据库实体父类
|
||||
*/
|
||||
public class DbEntity {
|
||||
private static final Object LOCK = new Object();
|
||||
protected int rowID = -1;
|
||||
private DbUtil mUtil = DbUtil.getInstance();
|
||||
|
||||
protected DbEntity() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有数据
|
||||
*
|
||||
* @return 没有数据返回null
|
||||
*/
|
||||
public static <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
return util.findAllData(clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询一组数据
|
||||
*
|
||||
* @return 没有数据返回null
|
||||
*/
|
||||
public static <T extends DbEntity> List<T> findDatas(Class<T> clazz, @NonNull String[] wheres,
|
||||
@NonNull String[] values) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
return util.findData(clazz, wheres, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询一行数据
|
||||
*
|
||||
* @return 没有数据返回null
|
||||
*/
|
||||
public static <T extends DbEntity> T findData(Class<T> clazz, @NonNull String[] wheres,
|
||||
@NonNull String[] values) {
|
||||
DbUtil util = DbUtil.getInstance();
|
||||
List<T> datas = util.findData(clazz, wheres, values);
|
||||
return datas == null ? null : datas.size() > 0 ? datas.get(0) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有行的rowid
|
||||
*/
|
||||
public int[] getRowIds() {
|
||||
return mUtil.getRowId(getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取rowid
|
||||
*/
|
||||
public int getRowId(@NonNull Object[] wheres, @NonNull Object[] values) {
|
||||
return mUtil.getRowId(getClass(), wheres, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除当前数据
|
||||
*/
|
||||
public void deleteData() {
|
||||
mUtil.delData(getClass(), new Object[] { "rowid" }, new Object[] { rowID });
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据条件删除数据
|
||||
*/
|
||||
public void deleteData(@NonNull Object[] wheres, @NonNull Object[] values) {
|
||||
mUtil.delData(getClass(), wheres, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改数据
|
||||
*/
|
||||
public void update() {
|
||||
mUtil.modifyData(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存自身,如果表中已经有数据,则更新数据,否则插入数据
|
||||
*/
|
||||
public void save() {
|
||||
synchronized (LOCK) {
|
||||
if (mUtil.tableExists(getClass()) && thisIsExist()) {
|
||||
update();
|
||||
} else {
|
||||
insert();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找数据在表中是否存在
|
||||
*/
|
||||
private boolean thisIsExist() {
|
||||
return findData(getClass(), new String[] { "rowid" }, new String[] { rowID + "" }) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
public void insert() {
|
||||
mUtil.insertData(this);
|
||||
updateRowID();
|
||||
}
|
||||
|
||||
private void updateRowID() {
|
||||
try {
|
||||
Field[] fields = CommonUtil.getFields(getClass());
|
||||
List<String> where = new ArrayList<>();
|
||||
List<String> values = new ArrayList<>();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
Ignore ignore = field.getAnnotation(Ignore.class);
|
||||
if (ignore != null && ignore.value()) {
|
||||
continue;
|
||||
}
|
||||
where.add(field.getName());
|
||||
values.add(field.get(this) + "");
|
||||
}
|
||||
DbEntity entity = findData(getClass(), where.toArray(new String[where.size()]),
|
||||
values.toArray(new String[values.size()]));
|
||||
if (entity != null) {
|
||||
rowID = entity.rowID;
|
||||
}
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
451
Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
Normal file
451
Aria/src/main/java/com/arialyy/aria/orm/DbUtil.java
Normal file
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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 android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.util.CommonUtil;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by AriaLyy on 2015/2/11.
|
||||
* 数据库操作工具
|
||||
*/
|
||||
public class DbUtil {
|
||||
private static final String TAG = "DbUtil";
|
||||
private static final Object LOCK = new Object();
|
||||
private volatile static DbUtil INSTANCE = null;
|
||||
private int CREATE_TABLE = 0;
|
||||
private int TABLE_EXISTS = 1;
|
||||
private int INSERT_DATA = 2;
|
||||
private int MODIFY_DATA = 3;
|
||||
private int FIND_DATA = 4;
|
||||
private int FIND_ALL_DATA = 5;
|
||||
private int DEL_DATA = 6;
|
||||
private int ROW_ID = 7;
|
||||
private SQLiteDatabase mDb;
|
||||
private SqlHelper mHelper;
|
||||
|
||||
private DbUtil() {
|
||||
|
||||
}
|
||||
|
||||
private DbUtil(Context context) {
|
||||
mHelper = new SqlHelper(context.getApplicationContext());
|
||||
}
|
||||
|
||||
public static DbUtil init(Context context) {
|
||||
if (context instanceof Application) {
|
||||
synchronized (LOCK) {
|
||||
if (INSTANCE == null) {
|
||||
INSTANCE = new DbUtil(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
protected static DbUtil getInstance() {
|
||||
if (INSTANCE == null) {
|
||||
throw new NullPointerException("请在Application中调用init进行数据库工具注册注册");
|
||||
}
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除某条数据
|
||||
*/
|
||||
synchronized <T extends DbEntity> void delData(Class<T> clazz, @NonNull Object[] wheres,
|
||||
@NonNull Object[] values) {
|
||||
mDb = mHelper.getWritableDatabase();
|
||||
if (wheres.length <= 0 || values.length <= 0) {
|
||||
Log.e(TAG, "输入删除条件");
|
||||
return;
|
||||
} else if (wheres.length != values.length) {
|
||||
Log.e(TAG, "key 和 vaule 长度不相等");
|
||||
return;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("DELETE FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE ");
|
||||
int i = 0;
|
||||
for (Object where : wheres) {
|
||||
sb.append(where).append("=").append("'").append(values[i]).append("'");
|
||||
sb.append(i >= wheres.length - 1 ? "" : ",");
|
||||
i++;
|
||||
}
|
||||
print(DEL_DATA, sb.toString());
|
||||
mDb.execSQL(sb.toString());
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改某行数据
|
||||
*/
|
||||
synchronized void modifyData(DbEntity dbEntity) {
|
||||
mDb = mHelper.getWritableDatabase();
|
||||
Class<?> clazz = dbEntity.getClass();
|
||||
Field[] fields = CommonUtil.getFields(clazz);
|
||||
if (fields != null && fields.length > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("UPDATE ").append(CommonUtil.getClassName(dbEntity)).append(" SET ");
|
||||
int i = 0;
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(i > 0 ? ", " : "");
|
||||
try {
|
||||
sb.append(field.getName())
|
||||
.append("='")
|
||||
.append(field.get(dbEntity).toString())
|
||||
.append("'");
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
sb.append(" where rowid=").append(dbEntity.rowID);
|
||||
print(MODIFY_DATA, sb.toString());
|
||||
mDb.execSQL(sb.toString());
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 遍历所有数据
|
||||
*/
|
||||
synchronized <T extends DbEntity> List<T> findAllData(Class<T> clazz) {
|
||||
if (!tableExists(clazz)) {
|
||||
createTable(clazz);
|
||||
}
|
||||
mDb = mHelper.getReadableDatabase();
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz));
|
||||
print(FIND_ALL_DATA, sb.toString());
|
||||
Cursor cursor = mDb.rawQuery(sb.toString(), null);
|
||||
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 条件查寻数据
|
||||
*/
|
||||
synchronized <T extends DbEntity> List<T> findData(Class<T> clazz, @NonNull String[] wheres,
|
||||
@NonNull String[] values) {
|
||||
if (!tableExists(clazz)) {
|
||||
createTable(clazz);
|
||||
}
|
||||
mDb = mHelper.getReadableDatabase();
|
||||
if (wheres.length <= 0 || values.length <= 0) {
|
||||
Log.e(TAG, "请输入查询条件");
|
||||
return null;
|
||||
} else if (wheres.length != values.length) {
|
||||
Log.e(TAG, "key 和 vaule 长度不相等");
|
||||
return null;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid, * FROM ").append(CommonUtil.getClassName(clazz)).append(" where ");
|
||||
int i = 0;
|
||||
for (Object where : wheres) {
|
||||
sb.append(where).append("=").append("'").append(values[i]).append("'");
|
||||
sb.append(i >= wheres.length - 1 ? "" : " AND ");
|
||||
i++;
|
||||
}
|
||||
print(FIND_DATA, sb.toString());
|
||||
Cursor cursor = mDb.rawQuery(sb.toString(), null);
|
||||
return cursor.getCount() > 0 ? newInstanceEntity(clazz, cursor) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 插入数据
|
||||
*/
|
||||
synchronized void insertData(DbEntity dbEntity) {
|
||||
Class<?> clazz = dbEntity.getClass();
|
||||
if (!tableExists(clazz)) {
|
||||
createTable(clazz);
|
||||
}
|
||||
mDb = mHelper.getWritableDatabase();
|
||||
Field[] fields = CommonUtil.getFields(clazz);
|
||||
if (fields != null && fields.length > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("INSERT INTO ").append(CommonUtil.getClassName(dbEntity)).append("(");
|
||||
int i = 0;
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(i > 0 ? ", " : "");
|
||||
sb.append(field.getName());
|
||||
i++;
|
||||
}
|
||||
sb.append(") VALUES (");
|
||||
i = 0;
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(i > 0 ? ", " : "");
|
||||
sb.append("'");
|
||||
try {
|
||||
sb.append(field.get(dbEntity)).append("'");
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
sb.append(")");
|
||||
print(INSERT_DATA, sb.toString());
|
||||
mDb.execSQL(sb.toString());
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* 查找某张表是否存在
|
||||
*/
|
||||
synchronized boolean tableExists(Class clazz) {
|
||||
if (mDb == null || !mDb.isOpen()) {
|
||||
mDb = mHelper.getReadableDatabase();
|
||||
}
|
||||
Cursor cursor = null;
|
||||
try {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT COUNT(*) AS c FROM sqlite_master WHERE type='table' AND name='");
|
||||
sb.append(CommonUtil.getClassName(clazz));
|
||||
sb.append("'");
|
||||
print(TABLE_EXISTS, sb.toString());
|
||||
cursor = mDb.rawQuery(sb.toString(), null);
|
||||
if (cursor != null && cursor.moveToNext()) {
|
||||
int count = cursor.getInt(0);
|
||||
if (count > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
if (cursor != null) cursor.close();
|
||||
close();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建表
|
||||
*/
|
||||
private synchronized void createTable(Class clazz) {
|
||||
if (mDb == null || !mDb.isOpen()) {
|
||||
mDb = mHelper.getWritableDatabase();
|
||||
}
|
||||
Field[] fields = CommonUtil.getFields(clazz);
|
||||
if (fields != null && fields.length > 0) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("create table ").append(CommonUtil.getClassName(clazz)).append("(");
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
sb.append(field.getName());
|
||||
Class<?> type = field.getType();
|
||||
if (type == String.class) {
|
||||
sb.append(" varchar");
|
||||
} else if (type == int.class || type == Integer.class) {
|
||||
sb.append(" interger");
|
||||
} else if (type == float.class || type == Float.class) {
|
||||
sb.append(" float");
|
||||
} else if (type == double.class || type == Double.class) {
|
||||
sb.append(" double");
|
||||
} else if (type == long.class || type == Long.class) {
|
||||
sb.append(" bigint");
|
||||
} else if (type == boolean.class || type == Boolean.class) {
|
||||
sb.append(" boolean");
|
||||
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
|
||||
sb.append(" data");
|
||||
} else if (type == byte.class || type == Byte.class) {
|
||||
sb.append(" blob");
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
sb.append(",");
|
||||
}
|
||||
String str = sb.toString();
|
||||
str = str.substring(0, str.length() - 1) + ");";
|
||||
print(CREATE_TABLE, str);
|
||||
mDb.execSQL(str);
|
||||
}
|
||||
close();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true 忽略该字段
|
||||
*/
|
||||
private boolean ignoreField(Field field) {
|
||||
// field.isSynthetic(), 使用as热启动App时,AS会自动给你的clss添加change字段
|
||||
Ignore ignore = field.getAnnotation(Ignore.class);
|
||||
return (ignore != null && ignore.value()) || field.isSynthetic();
|
||||
}
|
||||
|
||||
/**
|
||||
* 打印数据库日志
|
||||
*
|
||||
* @param type {@link DbUtil}
|
||||
*/
|
||||
private void print(int type, String sql) {
|
||||
if (true) {
|
||||
return;
|
||||
}
|
||||
String str = "";
|
||||
switch (type) {
|
||||
case 0:
|
||||
str = "创建表 >>>> ";
|
||||
break;
|
||||
case 1:
|
||||
str = "表是否存在 >>>> ";
|
||||
break;
|
||||
case 2:
|
||||
str = "插入数据 >>>> ";
|
||||
break;
|
||||
case 3:
|
||||
str = "修改数据 >>>> ";
|
||||
break;
|
||||
case 4:
|
||||
str = "查询一行数据 >>>> ";
|
||||
break;
|
||||
case 5:
|
||||
str = "遍历整个数据库 >>>> ";
|
||||
break;
|
||||
}
|
||||
Log.v(TAG, str + sql);
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭数据库
|
||||
*/
|
||||
private synchronized void close() {
|
||||
if (mDb != null) {
|
||||
mDb.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所在行Id
|
||||
*/
|
||||
synchronized int[] getRowId(Class clazz) {
|
||||
mDb = mHelper.getReadableDatabase();
|
||||
Cursor cursor = mDb.rawQuery("SELECT rowid, * FROM " + CommonUtil.getClassName(clazz), null);
|
||||
int[] ids = new int[cursor.getCount()];
|
||||
int i = 0;
|
||||
while (cursor.moveToNext()) {
|
||||
ids[i] = cursor.getInt(cursor.getColumnIndex("rowid"));
|
||||
i++;
|
||||
}
|
||||
cursor.close();
|
||||
close();
|
||||
return ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取行Id
|
||||
*/
|
||||
synchronized int getRowId(Class clazz, Object[] wheres, Object[] values) {
|
||||
mDb = mHelper.getReadableDatabase();
|
||||
if (wheres.length <= 0 || values.length <= 0) {
|
||||
Log.e(TAG, "请输入删除条件");
|
||||
return -1;
|
||||
} else if (wheres.length != values.length) {
|
||||
Log.e(TAG, "key 和 vaule 长度不相等");
|
||||
return -1;
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("SELECT rowid FROM ").append(CommonUtil.getClassName(clazz)).append(" WHERE ");
|
||||
int i = 0;
|
||||
for (Object where : wheres) {
|
||||
sb.append(where).append("=").append("'").append(values[i]).append("'");
|
||||
sb.append(i >= wheres.length - 1 ? "" : ",");
|
||||
i++;
|
||||
}
|
||||
print(ROW_ID, sb.toString());
|
||||
Cursor c = mDb.rawQuery(sb.toString(), null);
|
||||
int id = c.getColumnIndex("rowid");
|
||||
c.close();
|
||||
close();
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据数据游标创建一个具体的对象
|
||||
*/
|
||||
private synchronized <T extends DbEntity> List<T> newInstanceEntity(Class<T> clazz,
|
||||
Cursor cursor) {
|
||||
Field[] fields = CommonUtil.getFields(clazz);
|
||||
List<T> entitys = new ArrayList<>();
|
||||
if (fields != null && fields.length > 0) {
|
||||
try {
|
||||
while (cursor.moveToNext()) {
|
||||
T entity = clazz.newInstance();
|
||||
for (Field field : fields) {
|
||||
field.setAccessible(true);
|
||||
if (ignoreField(field)) {
|
||||
continue;
|
||||
}
|
||||
Class<?> type = field.getType();
|
||||
int column = cursor.getColumnIndex(field.getName());
|
||||
if (type == String.class) {
|
||||
field.set(entity, cursor.getString(column));
|
||||
} else if (type == int.class || type == Integer.class) {
|
||||
field.setInt(entity, cursor.getInt(column));
|
||||
} else if (type == float.class || type == Float.class) {
|
||||
field.setFloat(entity, cursor.getFloat(column));
|
||||
} else if (type == double.class || type == Double.class) {
|
||||
field.setDouble(entity, cursor.getDouble(column));
|
||||
} else if (type == long.class || type == Long.class) {
|
||||
field.setLong(entity, cursor.getLong(column));
|
||||
} else if (type == boolean.class || type == Boolean.class) {
|
||||
field.setBoolean(entity, !cursor.getString(column).equalsIgnoreCase("false"));
|
||||
} else if (type == java.util.Date.class || type == java.sql.Date.class) {
|
||||
field.set(entity, new Date(cursor.getString(column)));
|
||||
} else if (type == byte[].class) {
|
||||
field.set(entity, cursor.getBlob(column));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
entity.rowID = cursor.getInt(cursor.getColumnIndex("rowid"));
|
||||
entitys.add(entity);
|
||||
Log.d(TAG, "rowid ==> " + entity.rowID);
|
||||
}
|
||||
} catch (InstantiationException e) {
|
||||
e.printStackTrace();
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
close();
|
||||
return entitys;
|
||||
}
|
||||
}
|
31
Aria/src/main/java/com/arialyy/aria/orm/Id.java
Normal file
31
Aria/src/main/java/com/arialyy/aria/orm/Id.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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 lyy on 2015/11/2.
|
||||
* 表ID字段指定
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Id {
|
||||
int value() default -1;
|
||||
}
|
31
Aria/src/main/java/com/arialyy/aria/orm/Ignore.java
Normal file
31
Aria/src/main/java/com/arialyy/aria/orm/Ignore.java
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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 lyy on 2015/11/2.
|
||||
* 忽略某个字段
|
||||
*/
|
||||
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Ignore {
|
||||
boolean value() default true;
|
||||
}
|
53
Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
Normal file
53
Aria/src/main/java/com/arialyy/aria/orm/SqlHelper.java
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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 android.content.Context;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.database.sqlite.SQLiteOpenHelper;
|
||||
import android.text.TextUtils;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2015/11/2.
|
||||
* sql帮助类
|
||||
*/
|
||||
public class SqlHelper extends SQLiteOpenHelper {
|
||||
protected static String DB_NAME;
|
||||
protected static int VERSION = -1;
|
||||
|
||||
static {
|
||||
if (TextUtils.isEmpty(DB_NAME)) {
|
||||
DB_NAME = "AriaLyyDb";
|
||||
}
|
||||
if (VERSION == -1) {
|
||||
VERSION = 1;
|
||||
}
|
||||
}
|
||||
|
||||
public SqlHelper(Context context) {
|
||||
super(context, DB_NAME, null, VERSION);
|
||||
}
|
||||
|
||||
@Override public void onCreate(SQLiteDatabase db) {
|
||||
|
||||
}
|
||||
|
||||
@Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
|
||||
}
|
||||
}
|
64
Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
Normal file
64
Aria/src/main/java/com/arialyy/aria/util/CheckUtil.java
Normal file
@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.util;
|
||||
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by Lyy on 2016/9/23.
|
||||
* 检查帮助类
|
||||
*/
|
||||
public class CheckUtil {
|
||||
private static final String TAG = "CheckUtil";
|
||||
|
||||
/**
|
||||
* 检测下载实体是否合法
|
||||
*
|
||||
* @param entity 下载实体
|
||||
* @return 合法(true)
|
||||
*/
|
||||
public static boolean checkDownloadEntity(DownloadEntity entity) {
|
||||
if (entity == null) {
|
||||
Log.w(TAG, "下载实体不能为空");
|
||||
return false;
|
||||
} else if (TextUtils.isEmpty(entity.getDownloadUrl())) {
|
||||
Log.w(TAG, "下载链接不能为空");
|
||||
return false;
|
||||
} else if (TextUtils.isEmpty(entity.getFileName())) {
|
||||
Log.w(TAG, "文件名不能为空");
|
||||
return false;
|
||||
} else if (TextUtils.isEmpty(entity.getDownloadPath())) {
|
||||
Log.w(TAG, "存储地址不能为空");
|
||||
return false;
|
||||
}
|
||||
String fileName = entity.getFileName();
|
||||
if (fileName.contains(" ")) {
|
||||
fileName = fileName.replace(" ", "_");
|
||||
}
|
||||
String dPath = entity.getDownloadPath();
|
||||
File file = new File(dPath);
|
||||
if (file.isDirectory()) {
|
||||
dPath += fileName;
|
||||
entity.setDownloadPath(dPath);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
303
Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
Normal file
303
Aria/src/main/java/com/arialyy/aria/util/CommonUtil.java
Normal file
@ -0,0 +1,303 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.util;
|
||||
|
||||
import android.util.Log;
|
||||
import com.arialyy.aria.core.command.CmdFactory;
|
||||
import com.arialyy.aria.core.DownloadEntity;
|
||||
import com.arialyy.aria.core.command.IDownloadCmd;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/1/22.
|
||||
*/
|
||||
public class CommonUtil {
|
||||
private static final String TAG = "util";
|
||||
|
||||
public static IDownloadCmd createCmd(Object target, DownloadEntity entity, int cmd) {
|
||||
return CmdFactory.getInstance().createCmd(target, entity, cmd);
|
||||
}
|
||||
|
||||
public static IDownloadCmd createCmd(DownloadEntity entity, int cmd) {
|
||||
return CmdFactory.getInstance().createCmd(entity, cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类里面的所在字段
|
||||
*/
|
||||
public static Field[] getFields(Class clazz) {
|
||||
Field[] fields = null;
|
||||
fields = clazz.getDeclaredFields();
|
||||
if (fields == null || fields.length == 0) {
|
||||
Class superClazz = clazz.getSuperclass();
|
||||
if (superClazz != null) {
|
||||
fields = getFields(superClazz);
|
||||
}
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类里面的指定对象,如果该类没有则从父类查询
|
||||
*/
|
||||
public static Field getField(Class clazz, String name) {
|
||||
Field field = null;
|
||||
try {
|
||||
field = clazz.getDeclaredField(name);
|
||||
} catch (NoSuchFieldException e) {
|
||||
try {
|
||||
field = clazz.getField(name);
|
||||
} catch (NoSuchFieldException e1) {
|
||||
if (clazz.getSuperclass() == null) {
|
||||
return field;
|
||||
} else {
|
||||
field = getField(clazz.getSuperclass(), name);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转hashcode
|
||||
*/
|
||||
public static int keyToHashCode(String str) {
|
||||
int total = 0;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char ch = str.charAt(i);
|
||||
if (ch == '-') ch = (char) 28; // does not contain the same last 5 bits as any letter
|
||||
if (ch == '\'') ch = (char) 29; // nor this
|
||||
total = (total * 33) + (ch & 0x1F);
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将key转换为16进制码
|
||||
*
|
||||
* @param key 缓存的key
|
||||
* @return 转换后的key的值, 系统便是通过该key来读写缓存
|
||||
*/
|
||||
public static String keyToHashKey(String key) {
|
||||
String cacheKey;
|
||||
try {
|
||||
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
|
||||
mDigest.update(key.getBytes());
|
||||
cacheKey = bytesToHexString(mDigest.digest());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
cacheKey = String.valueOf(key.hashCode());
|
||||
}
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将普通字符串转换为16位进制字符串
|
||||
*/
|
||||
public static String bytesToHexString(byte[] src) {
|
||||
StringBuilder stringBuilder = new StringBuilder("0x");
|
||||
if (src == null || src.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
char[] buffer = new char[2];
|
||||
for (byte aSrc : src) {
|
||||
buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
|
||||
buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
|
||||
stringBuilder.append(buffer);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象名
|
||||
*
|
||||
* @param obj 对象
|
||||
* @return 对象名
|
||||
*/
|
||||
public static String getClassName(Object obj) {
|
||||
String arrays[] = obj.getClass().getName().split("\\.");
|
||||
return arrays[arrays.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象名
|
||||
*
|
||||
* @param clazz clazz
|
||||
* @return 对象名
|
||||
*/
|
||||
public static String getClassName(Class clazz) {
|
||||
String arrays[] = clazz.getName().split("\\.");
|
||||
return arrays[arrays.length - 1];
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化文件大小
|
||||
*
|
||||
* @param size file.length() 获取文件大小
|
||||
*/
|
||||
public static String formatFileSize(double size) {
|
||||
double kiloByte = size / 1024;
|
||||
if (kiloByte < 1) {
|
||||
return size + "b";
|
||||
}
|
||||
|
||||
double megaByte = kiloByte / 1024;
|
||||
if (megaByte < 1) {
|
||||
BigDecimal result1 = new BigDecimal(Double.toString(kiloByte));
|
||||
return result1.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "k";
|
||||
}
|
||||
|
||||
double gigaByte = megaByte / 1024;
|
||||
if (gigaByte < 1) {
|
||||
BigDecimal result2 = new BigDecimal(Double.toString(megaByte));
|
||||
return result2.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "m";
|
||||
}
|
||||
|
||||
double teraBytes = gigaByte / 1024;
|
||||
if (teraBytes < 1) {
|
||||
BigDecimal result3 = new BigDecimal(Double.toString(gigaByte));
|
||||
return result3.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "g";
|
||||
}
|
||||
BigDecimal result4 = new BigDecimal(teraBytes);
|
||||
return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString() + "t";
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建目录 当目录不存在的时候创建文件,否则返回false
|
||||
*/
|
||||
public static boolean createDir(String path) {
|
||||
File file = new File(path);
|
||||
if (!file.exists()) {
|
||||
if (!file.mkdirs()) {
|
||||
Log.d(TAG, "创建失败,请检查路径和是否配置文件权限!");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建文件 当文件不存在的时候就创建一个文件,否则直接返回文件
|
||||
*/
|
||||
public static File createFile(String path) {
|
||||
File file = new File(path);
|
||||
if (!file.getParentFile().exists()) {
|
||||
Log.d(TAG, "目标文件所在路径不存在,准备创建……");
|
||||
if (!createDir(file.getParent())) {
|
||||
Log.d(TAG, "创建目录文件所在的目录失败!文件路径【" + path + "】");
|
||||
}
|
||||
}
|
||||
// 创建目标文件
|
||||
try {
|
||||
if (!file.exists()) {
|
||||
if (file.createNewFile()) {
|
||||
Log.d(TAG, "创建文件成功:" + file.getAbsolutePath());
|
||||
}
|
||||
return file;
|
||||
} else {
|
||||
return file;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置打印的异常格式
|
||||
*/
|
||||
public static String getPrintException(Throwable ex) {
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("ExceptionDetailed:\n");
|
||||
err.append("====================Exception Info====================\n");
|
||||
err.append(ex.toString());
|
||||
err.append("\n");
|
||||
StackTraceElement[] stack = ex.getStackTrace();
|
||||
for (StackTraceElement stackTraceElement : stack) {
|
||||
err.append(stackTraceElement.toString()).append("\n");
|
||||
}
|
||||
Throwable cause = ex.getCause();
|
||||
if (cause != null) {
|
||||
err.append("【Caused by】: ");
|
||||
err.append(cause.toString());
|
||||
err.append("\n");
|
||||
StackTraceElement[] stackTrace = cause.getStackTrace();
|
||||
for (StackTraceElement stackTraceElement : stackTrace) {
|
||||
err.append(stackTraceElement.toString()).append("\n");
|
||||
}
|
||||
}
|
||||
err.append("===================================================");
|
||||
return err.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取下载配置文件
|
||||
*/
|
||||
public static Properties loadConfig(File file) {
|
||||
Properties properties = new Properties();
|
||||
FileInputStream fis = null;
|
||||
|
||||
try {
|
||||
fis = new FileInputStream(file);
|
||||
properties.load(fis);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (fis != null) {
|
||||
fis.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存配置文件
|
||||
*/
|
||||
public static void saveConfig(File file, Properties properties) {
|
||||
FileOutputStream fos = null;
|
||||
try {
|
||||
fos = new FileOutputStream(file, false);
|
||||
properties.store(fos, null);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
} finally {
|
||||
try {
|
||||
if (fos != null) {
|
||||
fos.flush();
|
||||
fos.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
71
Aria/src/main/java/com/arialyy/aria/util/PathUtil.java
Normal file
71
Aria/src/main/java/com/arialyy/aria/util/PathUtil.java
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2016 AriaLyy(DownloadUtil)
|
||||
*
|
||||
* 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.util;
|
||||
|
||||
import android.os.Environment;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
/**
|
||||
* Created by lyy on 2016/9/27.
|
||||
* 下载路径帮助类
|
||||
*/
|
||||
public class PathUtil {
|
||||
|
||||
/**
|
||||
* 下载链接转换保存路径
|
||||
*
|
||||
* @param downloadUrl 下载链接
|
||||
* @return 保存路径
|
||||
*/
|
||||
public static String urlconvertPath(String downloadUrl) {
|
||||
return Environment.getDownloadCacheDirectory().getPath() + "/" + StringToHashKey(downloadUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 字符串转换为hash码
|
||||
*/
|
||||
public static String StringToHashKey(String str) {
|
||||
String cacheKey;
|
||||
try {
|
||||
final MessageDigest mDigest = MessageDigest.getInstance("MD5");
|
||||
mDigest.update(str.getBytes());
|
||||
cacheKey = bytesToHexString(mDigest.digest());
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
cacheKey = String.valueOf(str.hashCode());
|
||||
}
|
||||
return cacheKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将普通字符串转换为16位进制字符串
|
||||
*/
|
||||
public static String bytesToHexString(byte[] src) {
|
||||
StringBuilder stringBuilder = new StringBuilder("0x");
|
||||
if (src == null || src.length <= 0) {
|
||||
return null;
|
||||
}
|
||||
char[] buffer = new char[2];
|
||||
for (byte aSrc : src) {
|
||||
buffer[0] = Character.forDigit((aSrc >>> 4) & 0x0F, 16);
|
||||
buffer[1] = Character.forDigit(aSrc & 0x0F, 16);
|
||||
stringBuilder.append(buffer);
|
||||
}
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
}
|
8
Aria/src/main/res/values/strings.xml
Normal file
8
Aria/src/main/res/values/strings.xml
Normal file
@ -0,0 +1,8 @@
|
||||
<resources>
|
||||
<string name="app_name">DownloadUtil</string>
|
||||
|
||||
<string name="error_entity_null">下载实体不能为空</string>
|
||||
<string name="error_download_url_null">下载链接不能为空</string>
|
||||
<string name="error_download_path_null">存储地址不能为空</string>
|
||||
<string name="error_file_name_null">文件名不能为空</string>
|
||||
</resources>
|
Reference in New Issue
Block a user