DownloadUtil 重命名为 Aria,代码已重构,使用起来更加简便

This commit is contained in:
AriaLyy
2016-12-06 23:09:59 +08:00
parent 458dca551f
commit 02420fe1f5
57 changed files with 189 additions and 176 deletions

3
Aria/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
/build
gradle.properties
downloadutil.iml

26
Aria/build.gradle Normal file
View 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
View 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
View 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 *;
#}

View File

@ -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);
}
}

View 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>

View 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;
}
}

View 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) {
}
}
}

View 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");
}
}
}

View 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;
}
}
}
}
}

View 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);
}
}

View 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();
}
}

View 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, "添加命令执行失败,【该任务已经存在】");
}
}
}

View File

@ -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);
}
}
}

View 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);
}
}

View File

@ -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();
}

View File

@ -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);
}
}

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}

View 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();
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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();
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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() {
}
}

View 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();
}
}
}
}
}

View File

@ -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();
}

View File

@ -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();
}

View 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);
}
}
}

View File

@ -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();
}
}

View 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();
}
}
}

View 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;
}
}

View 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;
}

View 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;
}

View 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) {
}
}

View 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;
}
}

View 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();
}
}
}
}

View 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();
}
}

View 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>