diff --git a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java index c57e6f01..d9972ac1 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java +++ b/Aria/src/main/java/com/arialyy/aria/core/AriaManager.java @@ -33,6 +33,7 @@ import com.arialyy.aria.core.inf.ICmd; import com.arialyy.aria.core.inf.IReceiver; import com.arialyy.aria.core.upload.UploadReceiver; import com.arialyy.aria.orm.DbUtil; +import com.arialyy.aria.util.FileUtil; import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -66,13 +67,7 @@ import org.xml.sax.SAXException; DbUtil.init(context.getApplicationContext()); APP = context.getApplicationContext(); regAppLifeCallback(context); - File dFile = new File(APP.getFilesDir().getPath() + Configuration.DOWNLOAD_CONFIG_FILE); - File uFile = new File(APP.getFilesDir().getPath() +Configuration.UPLOAD_CONFIG_FILE); - if (!dFile.exists() || !uFile.exists()) { - loadConfig(); - } - mDConfig = Configuration.DownloadConfig.getInstance(); - mUConfig = Configuration.UploadConfig.getInstance(); + initConfig(); } public static AriaManager getInstance(Context context) { @@ -98,7 +93,7 @@ import org.xml.sax.SAXException; SAXParser parser = factory.newSAXParser(); parser.parse(APP.getAssets().open("aria_config.xml"), helper); } catch (ParserConfigurationException | IOException | SAXException e) { - e.printStackTrace(); + Log.d(TAG, e.toString()); } } @@ -106,7 +101,7 @@ import org.xml.sax.SAXException; * 如果需要在代码中修改下载配置,请使用以下方法 * * @ //修改最大任务队列数 - * Aria.get(this).getDownloadConfig().setMaxTaskNum(3).saveAll(); + * Aria.get(this).getDownloadConfig().setMaxTaskNum(3); * */ public Configuration.DownloadConfig getDownloadConfig() { @@ -117,7 +112,7 @@ import org.xml.sax.SAXException; * 如果需要在代码中修改下载配置,请使用以下方法 * * @ //修改最大任务队列数 - * Aria.get(this).getUploadConfig().setMaxTaskNum(3).saveAll(); + * Aria.get(this).getUploadConfig().setMaxTaskNum(3); * */ public Configuration.UploadConfig getUploadConfig() { @@ -243,6 +238,29 @@ import org.xml.sax.SAXException; return key; } + /** + * 初始化配置文件 + */ + private void initConfig() { + //File dFile = new File(APP.getFilesDir().getPath() + Configuration.DOWNLOAD_CONFIG_FILE); + //File uFile = new File(APP.getFilesDir().getPath() + Configuration.UPLOAD_CONFIG_FILE); + File xmlFile = new File(APP.getFilesDir().getPath() + Configuration.XML_FILE); + if (!xmlFile.exists()) { + loadConfig(); + } else { + try { + String md5Code = FileUtil.getFileMD5(xmlFile); + if (!FileUtil.checkMD5(md5Code, APP.getAssets().open("aria_config.xml"))) { + loadConfig(); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + mDConfig = Configuration.DownloadConfig.getInstance(); + mUConfig = Configuration.UploadConfig.getInstance(); + } + /** * 注册APP生命周期回调 */ diff --git a/Aria/src/main/java/com/arialyy/aria/core/Configuration.java b/Aria/src/main/java/com/arialyy/aria/core/Configuration.java index 3ce98ac4..260281ac 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/Configuration.java +++ b/Aria/src/main/java/com/arialyy/aria/core/Configuration.java @@ -15,7 +15,6 @@ */ package com.arialyy.aria.core; -import android.util.Log; import com.arialyy.aria.core.queue.DownloadTaskQueue; import com.arialyy.aria.util.CommonUtil; import com.arialyy.aria.util.ReflectionUtil; @@ -32,6 +31,7 @@ import java.util.Properties; class Configuration { static final String DOWNLOAD_CONFIG_FILE = "/Aria/DownloadConfig.properties"; static final String UPLOAD_CONFIG_FILE = "/Aria/UploadConfig.properties"; + static final String XML_FILE = "/Aria/aria_config.xml"; /** * 通用配置 @@ -57,11 +57,11 @@ class Configuration { /** * 设置重试间隔,单位为毫秒,默认2000毫秒 */ - long reTryInterval = 2000; + int reTryInterval = 2000; /** * 设置url连接超时时间,单位为毫秒,默认5000毫秒 */ - long connectTimeOut = 5000; + int connectTimeOut = 5000; public boolean isOpenBreadCast() { return isOpenBreadCast; @@ -95,21 +95,21 @@ class Configuration { return this; } - public long getReTryInterval() { + public int getReTryInterval() { return reTryInterval; } - public BaseConfig setReTryInterval(long reTryInterval) { + public BaseConfig setReTryInterval(int reTryInterval) { this.reTryInterval = reTryInterval; saveKey("reTryInterval", reTryInterval + ""); return this; } - public long getConnectTimeOut() { + public int getConnectTimeOut() { return connectTimeOut; } - public BaseConfig setConnectTimeOut(long connectTimeOut) { + public BaseConfig setConnectTimeOut(int connectTimeOut) { this.connectTimeOut = connectTimeOut; saveKey("connectTimeOut", connectTimeOut + ""); return this; @@ -203,7 +203,7 @@ class Configuration { /** * 设置IO流读取时间,单位为毫秒,默认20000毫秒,该时间不能少于10000毫秒 */ - long iOTimeOut = 20 * 1000; + int iOTimeOut = 20 * 1000; /** * 设置写文件buff大小,该数值大小不能小于2048,数值变小,下载速度会变慢 */ @@ -221,11 +221,11 @@ class Configuration { */ int threadNum = 3; - public long getiOTimeOut() { + public int getIOTimeOut() { return iOTimeOut; } - public DownloadConfig setiOTimeOut(long iOTimeOut) { + public DownloadConfig setIOTimeOut(int iOTimeOut) { this.iOTimeOut = iOTimeOut; saveKey("iOTimeOut", iOTimeOut + ""); return this; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java index aa46891d..f2ddb057 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadEntity.java @@ -43,10 +43,19 @@ public class DownloadEntity extends DbEntity implements Parcelable, IEntity { private long completeTime; //完成时间 private boolean isRedirect = false; private String redirectUrl = ""; //重定向链接 + private int threadNum; //下载线程数 public DownloadEntity() { } + public int getThreadNum() { + return threadNum; + } + + public void setThreadNum(int threadNum) { + this.threadNum = threadNum; + } + public String getStr() { return str; } @@ -191,6 +200,8 @@ public class DownloadEntity extends DbEntity implements Parcelable, IEntity { + ", redirectUrl='" + redirectUrl + '\'' + + ", threadNum=" + + threadNum + '}'; } @@ -212,6 +223,7 @@ public class DownloadEntity extends DbEntity implements Parcelable, IEntity { dest.writeLong(this.completeTime); dest.writeByte(this.isRedirect ? (byte) 1 : (byte) 0); dest.writeString(this.redirectUrl); + dest.writeInt(this.threadNum); } protected DownloadEntity(Parcel in) { @@ -228,6 +240,7 @@ public class DownloadEntity extends DbEntity implements Parcelable, IEntity { this.completeTime = in.readLong(); this.isRedirect = in.readByte() != 0; this.redirectUrl = in.readString(); + this.threadNum = in.readInt(); } @Ignore public static final Creator CREATOR = new Creator() { diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java index 934ff001..8c815ee9 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadStateConstance.java @@ -23,10 +23,10 @@ final class DownloadStateConstance { int CANCEL_NUM = 0; int STOP_NUM = 0; int FAIL_NUM = 0; - int CONNECT_TIME_OUT = 5000 * 4; //连接超时时间 - int READ_TIME_OUT = 1000 * 20; //流读取的超时时间 + int CONNECT_TIME_OUT; //连接超时时间 + int READ_TIME_OUT; //流读取的超时时间 int COMPLETE_THREAD_NUM = 0; - int THREAD_NUM = 3; + int THREAD_NUM; long CURRENT_LOCATION = 0; boolean isDownloading = false; boolean isCancel = false; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java index 4d87e055..f6bd01a3 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/DownloadUtil.java @@ -19,6 +19,7 @@ package com.arialyy.aria.core.download; import android.content.Context; import android.util.Log; import android.util.SparseArray; +import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.CheckUtil; import com.arialyy.aria.util.CommonUtil; @@ -34,7 +35,7 @@ import java.util.concurrent.Executors; * Created by lyy on 2015/8/25. * 下载工具类 */ -public class DownloadUtil implements IDownloadUtil, Runnable { +class DownloadUtil implements IDownloadUtil, Runnable { private static final String TAG = "DownloadUtil"; /** * 线程数 @@ -46,8 +47,7 @@ public class DownloadUtil implements IDownloadUtil, Runnable { private static final long SUB_LEN = 1024 * 1024; //下载监听 private IDownloadListener mListener; - private int mConnectTimeOut = 5000 * 4; //连接超时时间 - private int mReadTimeOut = 5000 * 20; //流读取的超时时间 + private int mConnectTimeOut = 0; //连接超时时间 private boolean isNewTask = true; private boolean isSupportBreakpoint = true; private Context mContext; @@ -57,34 +57,29 @@ public class DownloadUtil implements IDownloadUtil, Runnable { private File mDownloadFile; //下载的文件 private File mConfigFile;//下载信息配置文件 private SparseArray mTask = new SparseArray<>(); - private DownloadStateConstance mConstance; + private DownloadStateConstance CONSTANCE; DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener) { - this(context, entity, downloadListener, 3); - } - - DownloadUtil(Context context, DownloadTaskEntity entity, IDownloadListener downloadListener, - int threadNum) { - //CheckUtil.checkDownloadTaskEntity(entity.downloadEntity); CheckUtil.checkTaskEntity(entity); mDownloadEntity = entity.downloadEntity; mContext = context.getApplicationContext(); mDownloadTaskEntity = entity; mListener = downloadListener; - THREAD_NUM = threadNum; + // 线程下载数改变后,新的下载才会生效 mFixedThreadPool = Executors.newFixedThreadPool(Integer.MAX_VALUE); - mConstance = new DownloadStateConstance(); + CONSTANCE = new DownloadStateConstance(); init(); } private void init() { + mConnectTimeOut = AriaManager.getInstance(mContext).getDownloadConfig().getConnectTimeOut(); mDownloadFile = new File(mDownloadTaskEntity.downloadEntity.getDownloadPath()); //读取已完成的线程数 mConfigFile = new File( mContext.getFilesDir().getPath() + "/temp/" + mDownloadFile.getName() + ".properties"); try { if (!mConfigFile.exists()) { //记录文件被删除,则重新下载 - isNewTask = true; + handleNewTask(); CommonUtil.createFile(mConfigFile.getPath()); } else { isNewTask = !mDownloadFile.exists(); @@ -99,37 +94,23 @@ public class DownloadUtil implements IDownloadUtil, Runnable { return mListener; } - /** - * 设置连接超时时间 - */ - public void setConnectTimeOut(int timeOut) { - mConnectTimeOut = timeOut; - } - - /** - * 设置流读取的超时时间 - */ - public void setReadTimeOut(int readTimeOut) { - mReadTimeOut = readTimeOut; - } - /** * 获取当前下载位置 */ @Override public long getCurrentLocation() { - return mConstance.CURRENT_LOCATION; + return CONSTANCE.CURRENT_LOCATION; } @Override public boolean isDownloading() { - return mConstance.isDownloading; + return CONSTANCE.isDownloading; } /** * 取消下载 */ @Override public void cancelDownload() { - mConstance.isCancel = true; - mConstance.isDownloading = false; + CONSTANCE.isCancel = true; + CONSTANCE.isDownloading = false; mFixedThreadPool.shutdown(); for (int i = 0; i < THREAD_NUM; i++) { SingleThreadTask task = (SingleThreadTask) mTask.get(i); @@ -143,8 +124,8 @@ public class DownloadUtil implements IDownloadUtil, Runnable { * 停止下载 */ @Override public void stopDownload() { - mConstance.isStop = true; - mConstance.isDownloading = false; + CONSTANCE.isStop = true; + CONSTANCE.isDownloading = false; mFixedThreadPool.shutdown(); for (int i = 0; i < THREAD_NUM; i++) { SingleThreadTask task = (SingleThreadTask) mTask.get(i); @@ -184,7 +165,7 @@ public class DownloadUtil implements IDownloadUtil, Runnable { * 多线程断点续传下载文件,开始下载 */ @Override public void startDownload() { - mConstance.cleanState(); + CONSTANCE.cleanState(); mListener.onPre(); new Thread(this).start(); } @@ -195,7 +176,7 @@ public class DownloadUtil implements IDownloadUtil, Runnable { private void failDownload(String msg) { Log.e(TAG, msg); - mConstance.isDownloading = false; + CONSTANCE.isDownloading = false; stopDownload(); mListener.onFail(); } @@ -206,7 +187,7 @@ public class DownloadUtil implements IDownloadUtil, Runnable { HttpURLConnection conn = ConnectionHelp.handleConnection(url); conn = ConnectionHelp.setConnectParam(mDownloadTaskEntity, conn); conn.setRequestProperty("Range", "bytes=" + 0 + "-"); - conn.setConnectTimeout(mConnectTimeOut * 4); + conn.setConnectTimeout(mConnectTimeOut); conn.connect(); handleConnect(conn); } catch (IOException e) { @@ -283,7 +264,7 @@ public class DownloadUtil implements IDownloadUtil, Runnable { conn = ConnectionHelp.setConnectParam(mDownloadTaskEntity, conn); conn.setRequestProperty("Cookie", cookies); conn.setRequestProperty("Range", "bytes=" + 0 + "-"); - conn.setConnectTimeout(mConnectTimeOut * 4); + conn.setConnectTimeout(mConnectTimeOut); conn.connect(); handleConnect(conn); @@ -301,7 +282,7 @@ public class DownloadUtil implements IDownloadUtil, Runnable { int fileLength = conn.getContentLength(); if (fileLength < SUB_LEN) { THREAD_NUM = 1; - mConstance.THREAD_NUM = THREAD_NUM; + CONSTANCE.THREAD_NUM = THREAD_NUM; } Properties pro = createConfigFile(fileLength); int blockSize = fileLength / THREAD_NUM; @@ -322,14 +303,14 @@ public class DownloadUtil implements IDownloadUtil, Runnable { //如果有记录,则恢复下载 if (!isNewTask && record != null && Long.parseLong(record + "") > 0) { Long r = Long.parseLong(record + ""); - mConstance.CURRENT_LOCATION += r - startL; + CONSTANCE.CURRENT_LOCATION += r - startL; Log.d(TAG, "++++++++++ 线程_" + i + "_恢复下载 ++++++++++"); mListener.onChildResume(r); startL = r; recordL[rl] = i; rl++; } else { - isNewTask = true; + handleNewTask(); } if (isNewTask) { recordL[rl] = i; @@ -351,7 +332,6 @@ public class DownloadUtil implements IDownloadUtil, Runnable { ConfigEntity entity = new ConfigEntity(); long len = conn.getContentLength(); entity.FILE_SIZE = len; - //entity.DOWNLOAD_URL = mDownloadEntity.getDownloadUrl(); entity.DOWNLOAD_URL = mDownloadEntity.isRedirect() ? mDownloadEntity.getRedirectUrl() : mDownloadEntity.getDownloadUrl(); entity.TEMP_FILE = mDownloadFile; @@ -362,8 +342,8 @@ public class DownloadUtil implements IDownloadUtil, Runnable { entity.isSupportBreakpoint = isSupportBreakpoint; entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity; THREAD_NUM = 1; - mConstance.THREAD_NUM = THREAD_NUM; - SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity); + CONSTANCE.THREAD_NUM = THREAD_NUM; + SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity); mTask.put(0, task); mFixedThreadPool.execute(task); mListener.onPostPre(len); @@ -385,15 +365,16 @@ public class DownloadUtil implements IDownloadUtil, Runnable { //分配每条线程的下载区间 pro = CommonUtil.loadConfig(mConfigFile); if (pro.isEmpty()) { - isNewTask = true; + handleNewTask(); } else { + THREAD_NUM = pro.keySet().size(); for (int i = 0; i < THREAD_NUM; i++) { if (pro.getProperty(mDownloadFile.getName() + "_record_" + i) == null) { Object state = pro.getProperty(mDownloadFile.getName() + "_state_" + i); if (state != null && Integer.parseInt(state + "") == 1) { continue; } - isNewTask = true; + handleNewTask(); break; } } @@ -401,23 +382,31 @@ public class DownloadUtil implements IDownloadUtil, Runnable { return pro; } + /** + * 处理新任务 + */ + private void handleNewTask() { + isNewTask = true; + THREAD_NUM = AriaManager.getInstance(mContext).getDownloadConfig().getThreadNum(); + } + /** * 恢复记录地址 * * @return true 表示下载完成 */ private boolean resumeRecordLocation(int i, long startL, long endL) { - mConstance.CURRENT_LOCATION += endL - startL; + CONSTANCE.CURRENT_LOCATION += endL - startL; Log.d(TAG, "++++++++++ 线程_" + i + "_已经下载完成 ++++++++++"); - mConstance.COMPLETE_THREAD_NUM++; - mConstance.STOP_NUM++; - mConstance.CANCEL_NUM++; - if (mConstance.isComplete()) { + CONSTANCE.COMPLETE_THREAD_NUM++; + CONSTANCE.STOP_NUM++; + CONSTANCE.CANCEL_NUM++; + if (CONSTANCE.isComplete()) { if (mConfigFile.exists()) { mConfigFile.delete(); } mListener.onComplete(); - mConstance.isDownloading = false; + CONSTANCE.isDownloading = false; return true; } return false; @@ -439,7 +428,8 @@ public class DownloadUtil implements IDownloadUtil, Runnable { entity.CONFIG_FILE_PATH = mConfigFile.getPath(); entity.isSupportBreakpoint = isSupportBreakpoint; entity.DOWNLOAD_TASK_ENTITY = mDownloadTaskEntity; - SingleThreadTask task = new SingleThreadTask(mConstance, mListener, entity); + CONSTANCE.THREAD_NUM = THREAD_NUM; + SingleThreadTask task = new SingleThreadTask(CONSTANCE, mListener, entity); mTask.put(i, task); } @@ -447,10 +437,10 @@ public class DownloadUtil implements IDownloadUtil, Runnable { * 启动单线程下载任务 */ private void startSingleTask(int[] recordL) { - if (mConstance.CURRENT_LOCATION > 0) { - mListener.onResume(mConstance.CURRENT_LOCATION); + if (CONSTANCE.CURRENT_LOCATION > 0) { + mListener.onResume(CONSTANCE.CURRENT_LOCATION); } else { - mListener.onStart(mConstance.CURRENT_LOCATION); + mListener.onStart(CONSTANCE.CURRENT_LOCATION); } for (int l : recordL) { if (l == -1) continue; diff --git a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java b/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java index bedf86c1..1ca9fe1b 100644 --- a/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java +++ b/Aria/src/main/java/com/arialyy/aria/core/download/SingleThreadTask.java @@ -15,10 +15,8 @@ */ package com.arialyy.aria.core.download; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; import android.util.Log; +import com.arialyy.aria.core.AriaManager; import com.arialyy.aria.util.BufferedRandomAccessFile; import com.arialyy.aria.util.CommonUtil; import java.io.File; @@ -34,35 +32,34 @@ import java.util.Properties; * 下载线程 */ final class SingleThreadTask implements Runnable { - private static final String TAG = "SingleThreadTask"; - // TODO: 2017/2/22 不能使用1024 否则最大速度不能超过3m - private static final int BUF_SIZE = 8192; + private static final String TAG = "SingleThreadTask"; private DownloadUtil.ConfigEntity mConfigEntity; private String mConfigFPath; private long mChildCurrentLocation = 0; private static final Object LOCK = new Object(); - private int mBufSize = 8192; - //private int mBufSize = 64; + private int mBufSize; private IDownloadListener mListener; - private DownloadStateConstance mConstance; + private DownloadStateConstance CONSTANCE; SingleThreadTask(DownloadStateConstance constance, IDownloadListener listener, DownloadUtil.ConfigEntity downloadInfo) { - mConstance = constance; + AriaManager manager = AriaManager.getInstance(AriaManager.APP); + CONSTANCE = constance; + CONSTANCE.CONNECT_TIME_OUT = manager.getDownloadConfig().getConnectTimeOut(); + CONSTANCE.READ_TIME_OUT = manager.getDownloadConfig().getIOTimeOut(); mListener = listener; this.mConfigEntity = downloadInfo; if (mConfigEntity.isSupportBreakpoint) { mConfigFPath = downloadInfo.CONFIG_FILE_PATH; } - //mBufSize = Configuration_1.getInstance().getMaxSpeed(); + mBufSize = manager.getDownloadConfig().getBuffSize(); } @Override public void run() { - HttpURLConnection conn = null; - InputStream is = null; + HttpURLConnection conn; + InputStream is; try { URL url = new URL(mConfigEntity.DOWNLOAD_URL); - //conn = (HttpURLConnection) url.openConnection(); conn = ConnectionHelp.handleConnection(url); if (mConfigEntity.isSupportBreakpoint) { Log.d(TAG, "线程_" @@ -79,8 +76,8 @@ final class SingleThreadTask implements Runnable { Log.w(TAG, "该下载不支持断点"); } conn = ConnectionHelp.setConnectParam(mConfigEntity.DOWNLOAD_TASK_ENTITY, conn); - conn.setConnectTimeout(mConstance.CONNECT_TIME_OUT); - conn.setReadTimeout(mConstance.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 + conn.setConnectTimeout(CONSTANCE.CONNECT_TIME_OUT); + conn.setReadTimeout(CONSTANCE.READ_TIME_OUT); //设置读取流的等待时间,必须设置该参数 is = conn.getInputStream(); //创建可设置位置的文件 BufferedRandomAccessFile file = @@ -92,10 +89,10 @@ final class SingleThreadTask implements Runnable { //当前子线程的下载位置 mChildCurrentLocation = mConfigEntity.START_LOCATION; while ((len = is.read(buffer)) != -1) { - if (mConstance.isCancel) { + if (CONSTANCE.isCancel) { break; } - if (mConstance.isStop) { + if (CONSTANCE.isStop) { break; } //把下载数据数据写入文件 @@ -106,11 +103,11 @@ final class SingleThreadTask implements Runnable { //close 为阻塞的,需要使用线程池来处理 is.close(); conn.disconnect(); - if (mConstance.isCancel) { + if (CONSTANCE.isCancel) { return; } //停止状态不需要删除记录文件 - if (mConstance.isStop) { + if (CONSTANCE.isStop) { return; } //支持断点的处理 @@ -119,29 +116,29 @@ final class SingleThreadTask implements Runnable { writeConfig(mConfigEntity.TEMP_FILE.getName() + "_state_" + mConfigEntity.THREAD_ID, 1 + ""); mListener.onChildComplete(mConfigEntity.END_LOCATION); - mConstance.COMPLETE_THREAD_NUM++; - if (mConstance.isComplete()) { + CONSTANCE.COMPLETE_THREAD_NUM++; + if (CONSTANCE.isComplete()) { File configFile = new File(mConfigFPath); if (configFile.exists()) { configFile.delete(); } - mConstance.isDownloading = false; + CONSTANCE.isDownloading = false; mListener.onComplete(); } } else { Log.i(TAG, "下载任务完成"); - mConstance.isDownloading = false; + CONSTANCE.isDownloading = false; mListener.onComplete(); } } catch (MalformedURLException e) { - mConstance.FAIL_NUM++; + CONSTANCE.FAIL_NUM++; failDownload(mConfigEntity, mChildCurrentLocation, "下载链接异常", e); } catch (IOException e) { - mConstance.FAIL_NUM++; + CONSTANCE.FAIL_NUM++; failDownload(mConfigEntity, mChildCurrentLocation, "下载失败【" + mConfigEntity.DOWNLOAD_URL + "】", e); } catch (Exception e) { - mConstance.FAIL_NUM++; + CONSTANCE.FAIL_NUM++; failDownload(mConfigEntity, mChildCurrentLocation, "获取流失败", e); } } @@ -153,7 +150,7 @@ final class SingleThreadTask implements Runnable { synchronized (LOCK) { try { if (mConfigEntity.isSupportBreakpoint) { - mConstance.STOP_NUM++; + CONSTANCE.STOP_NUM++; String location = String.valueOf(mChildCurrentLocation); Log.d(TAG, "thread_" + mConfigEntity.THREAD_ID @@ -161,15 +158,15 @@ final class SingleThreadTask implements Runnable { + mChildCurrentLocation); writeConfig(mConfigEntity.TEMP_FILE.getName() + "_record_" + mConfigEntity.THREAD_ID, location); - if (mConstance.isStop()) { + if (CONSTANCE.isStop()) { Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++"); - mConstance.isDownloading = false; - mListener.onStop(mConstance.CURRENT_LOCATION); + CONSTANCE.isDownloading = false; + mListener.onStop(CONSTANCE.CURRENT_LOCATION); } } else { Log.d(TAG, "++++++++++++++++ onStop +++++++++++++++++"); - mConstance.isDownloading = false; - mListener.onStop(mConstance.CURRENT_LOCATION); + CONSTANCE.isDownloading = false; + mListener.onStop(CONSTANCE.CURRENT_LOCATION); } } catch (IOException e) { e.printStackTrace(); @@ -183,44 +180,20 @@ final class SingleThreadTask implements Runnable { private void progress(long len) { synchronized (LOCK) { mChildCurrentLocation += len; - mConstance.CURRENT_LOCATION += len; - mListener.onProgress(mConstance.CURRENT_LOCATION); - //mHandler.sendEmptyMessage(1); - //mHandler.post(t); + CONSTANCE.CURRENT_LOCATION += len; + mListener.onProgress(CONSTANCE.CURRENT_LOCATION); } } - Handler mHandler = new Handler(Looper.getMainLooper()) { - @Override public void handleMessage(Message msg) { - super.handleMessage(msg); - mListener.onProgress(mConstance.CURRENT_LOCATION); - } - }; - - Thread t = new Thread(new Runnable() { - @Override public void run() { - mListener.onProgress(mConstance.CURRENT_LOCATION); - } - }); - - //Handler handler = new Handler(){ - // @Override public void handleMessage(Message msg) { - // super.handleMessage(msg); - // mListener.onProgress(mConstance.CURRENT_LOCATION); - // } - //}; - - Thread thread = new Thread(); - /** * 取消下载 */ protected void cancel() { synchronized (LOCK) { if (mConfigEntity.isSupportBreakpoint) { - mConstance.CANCEL_NUM++; + CONSTANCE.CANCEL_NUM++; Log.d(TAG, "++++++++++ thread_" + mConfigEntity.THREAD_ID + "_cancel ++++++++++"); - if (mConstance.isCancel()) { + if (CONSTANCE.isCancel()) { File configFile = new File(mConfigFPath); if (configFile.exists()) { configFile.delete(); @@ -229,12 +202,12 @@ final class SingleThreadTask implements Runnable { mConfigEntity.TEMP_FILE.delete(); } Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++"); - mConstance.isDownloading = false; + CONSTANCE.isDownloading = false; mListener.onCancel(); } } else { Log.d(TAG, "++++++++++++++++ onCancel +++++++++++++++++"); - mConstance.isDownloading = false; + CONSTANCE.isDownloading = false; mListener.onCancel(); } } @@ -247,8 +220,8 @@ final class SingleThreadTask implements Runnable { Exception ex) { synchronized (LOCK) { try { - mConstance.isDownloading = false; - mConstance.isStop = true; + CONSTANCE.isDownloading = false; + CONSTANCE.isStop = true; if (ex != null) { Log.e(TAG, CommonUtil.getPrintException(ex)); } @@ -257,7 +230,7 @@ final class SingleThreadTask implements Runnable { String location = String.valueOf(currentLocation); writeConfig(dEntity.TEMP_FILE.getName() + "_record_" + dEntity.THREAD_ID, location); } - if (mConstance.isFail()) { + if (CONSTANCE.isFail()) { Log.d(TAG, "++++++++++++++++ onFail +++++++++++++++++"); mListener.onFail(); } diff --git a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java index 8f2ed69c..d380c879 100644 --- a/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java +++ b/Aria/src/main/java/com/arialyy/aria/orm/DBConfig.java @@ -28,7 +28,7 @@ import java.util.Map; public class DBConfig { static Map mapping = new HashMap<>(); static String DB_NAME; - static int VERSION = 2; + static int VERSION = 3; static { if (TextUtils.isEmpty(DB_NAME)) { diff --git a/Aria/src/main/java/com/arialyy/aria/util/Configuration_1.java b/Aria/src/main/java/com/arialyy/aria/util/Configuration_1.java deleted file mode 100644 index d89ffed4..00000000 --- a/Aria/src/main/java/com/arialyy/aria/util/Configuration_1.java +++ /dev/null @@ -1,228 +0,0 @@ -/* - * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.arialyy.aria.util; - -import android.util.Log; -import com.arialyy.aria.core.AriaManager; -import java.io.File; -import java.io.IOException; -import java.util.Map; -import java.util.Properties; -import java.util.Set; -import java.util.WeakHashMap; - -/** - * Created by AriaL on 2016/12/8. - * 信息配置 - */ -public class Configuration_1 { - private static final String TAG = "Configuration_1"; - private static final String CONFIG_FILE = "/Aria/ADConfig.properties"; - /** - * 当前调度器最大下载数,默认最大下载数为 “2” - */ - private static final String DOWNLOAD_NUM = "DOWNLOAD_NUM"; - /** - * 失败重试次数,默认最多重试 10 次 - */ - private static final String RE_TRY_NUM = "RE_TRY_NUM"; - /** - * 是否打开下载广播,默认 false - */ - private static final String OPEN_BROADCAST = "OPEN_BROADCAST"; - /** - * 失败重试间隔时间,默认 4000 ms - */ - private static final String RE_TRY_INTERVAL = "RE_TRY_INTERVAL"; - /** - * 超时时间,默认 10000 ms - */ - private static final String DOWNLOAD_TIME_OUT = "DOWNLOAD_TIME_OUT"; - /** - * 设置最大速度 - */ - private static final String MAX_SPEED = "MAX_SPEED"; - - public static boolean isOpenBreadCast = false; - - private static Configuration_1 INSTANCE = null; - private File mConfigFile = null; - private static final Object LOCK = new Object(); - - public static Configuration_1 getInstance() { - if (INSTANCE == null) { - synchronized (LOCK) { - INSTANCE = new Configuration_1(); - } - } - return INSTANCE; - } - - private Configuration_1() { - mConfigFile = new File(AriaManager.APP.getFilesDir().getPath() + CONFIG_FILE); - try { - if (!mConfigFile.exists()) { - mConfigFile.getParentFile().mkdirs(); - mConfigFile.createNewFile(); - init(); - } else { - isOpenBreadCast = isOpenBroadcast(); - } - } catch (IOException e) { - e.printStackTrace(); - } - } - - private void init() { - Map config = new WeakHashMap<>(); - config.put(DOWNLOAD_NUM, 2 + ""); - config.put(RE_TRY_NUM, 10 + ""); - config.put(OPEN_BROADCAST, false + ""); - config.put(RE_TRY_INTERVAL, 4000 + ""); - config.put(DOWNLOAD_TIME_OUT, 10000 + ""); - config.put(MAX_SPEED, 64 + ""); - saveConfig(config); - } - - private void saveConfig(Map config) { - if (config == null || config.size() == 0) { - return; - } - Properties properties = CommonUtil.loadConfig(mConfigFile); - Set keys = config.keySet(); - for (String key : keys) { - properties.setProperty(key, config.get(key)); - } - CommonUtil.saveConfig(mConfigFile, properties); - } - - private void save(String key, String value) { - Map map = new WeakHashMap<>(); - map.put(key, value); - saveConfig(map); - } - - /** - * 设置最大下载速度 - */ - public void setMaxSpeed(Speed speed) { - save(MAX_SPEED, speed.buf + ""); - } - - /** - * 获取最大速度 - */ - public int getMaxSpeed() { - return Integer.parseInt(CommonUtil.loadConfig(mConfigFile).getProperty(MAX_SPEED, "8192")); - } - - /** - * 获取下载超时时间 - * - * @return 默认4000ms - */ - public int getTimeOut() { - return Integer.parseInt(CommonUtil.loadConfig(mConfigFile).getProperty(DOWNLOAD_TIME_OUT)); - } - - /** - * 设置重试间隔 - */ - public void setTimeOut(int timeOut) { - if (timeOut < 10000) { - Log.w(TAG, "下载超时时间不能小于 10000 ms"); - return; - } - save(DOWNLOAD_TIME_OUT, timeOut + ""); - } - - /** - * 获取失败重试间隔时间 - * - * @return 默认4000ms - */ - public int getReTryInterval() { - return Integer.parseInt(CommonUtil.loadConfig(mConfigFile).getProperty(RE_TRY_INTERVAL)); - } - - /** - * 设置重试间隔 - */ - public void setReTryInterval(int reTryInterval) { - if (reTryInterval < 4000) { - Log.w(TAG, "重试间隔不能小于4000ms"); - return; - } - save(RE_TRY_INTERVAL, reTryInterval + ""); - } - - /** - * 获取最大下载数 - * - * @return 默认返回2 - */ - public int getDownloadNum() { - return Integer.parseInt(CommonUtil.loadConfig(mConfigFile).getProperty(DOWNLOAD_NUM)); - } - - /** - * 设置最大下载数 - */ - public void setDownloadNum(int downloadNum) { - if (downloadNum < 1) { - Log.w(TAG, "最大下载数不能小于1"); - return; - } - save(DOWNLOAD_NUM, downloadNum + ""); - } - - /** - * 获取最大重试数 - * - * @return 默认返回 10 - */ - public int getReTryNum() { - return Integer.parseInt(CommonUtil.loadConfig(mConfigFile).getProperty(RE_TRY_NUM)); - } - - /** - * 设置重试数 - */ - public void setReTryNum(int reTryNum) { - if (reTryNum < 1) { - Log.w(TAG, "最大下载数不能小于1"); - return; - } - save(RE_TRY_NUM, reTryNum + ""); - } - - /** - * 是否打开下载广播 - * - * @return 默认false - */ - public boolean isOpenBroadcast() { - return Boolean.parseBoolean(CommonUtil.loadConfig(mConfigFile).getProperty(RE_TRY_NUM)); - } - - /** - * 设置是否打开下载广播 - */ - public void setOpenBroadcast(boolean openBroadcast) { - isOpenBreadCast = openBroadcast; - save(OPEN_BROADCAST, openBroadcast + ""); - } -} diff --git a/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java b/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java index 6fb9bf09..f6d4df5b 100644 --- a/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java +++ b/Aria/src/main/java/com/arialyy/aria/util/FileUtil.java @@ -15,105 +15,144 @@ */ package com.arialyy.aria.util; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageInfo; -import android.content.pm.PackageManager; -import android.graphics.drawable.Drawable; -import android.graphics.drawable.Icon; +import android.text.TextUtils; +import android.util.Log; import com.arialyy.aria.window.FileEntity; import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.List; /** * Created by Aria.Lao on 2017/3/21. */ - public class FileUtil { - Context mContext; + private static final String TAG = "FileUtil"; - public FileUtil(Context context) { - mContext = context; + /** + * 通过流创建文件 + */ + public static void createFileFormInputStream(InputStream is, String path) { + try { + FileOutputStream fos = new FileOutputStream(path); + byte[] buf = new byte[1376]; + while (is.read(buf) > 0) { + fos.write(buf, 0, buf.length); + } + is.close(); + fos.flush(); + fos.close(); + } catch (IOException e) { + e.printStackTrace(); + } } /** - * 文件列表 + * 校验文件MD5码 */ - public List loadFiles(String path) { - File file = new File(path); - File[] files = file.listFiles(); - List list = new ArrayList<>(); - for (File f : files) { - FileEntity entity = new FileEntity(); - entity.fileName = f.getName(); - //entity.fileInfo = getFileType(f.getPath()); - //entity.fileDrawable = getApkIcon(mContext, f.getPath()); - list.add(entity); + public static boolean checkMD5(String md5, File updateFile) { + if (TextUtils.isEmpty(md5) || updateFile == null) { + Log.e(TAG, "MD5 string empty or updateFile null"); + return false; } - return list; + + String calculatedDigest = getFileMD5(updateFile); + if (calculatedDigest == null) { + Log.e(TAG, "calculatedDigest null"); + return false; + } + return calculatedDigest.equalsIgnoreCase(md5); } /** - * 获取文件类型 + * 校验文件MD5码 */ - public FileType getFileType(String path) { - String exName = getExName(path); - String type = ""; - FileType fType = null; - if (exName.equalsIgnoreCase("apk")) { - fType = new FileType("应用", getApkIcon(path)); - } else if (exName.equalsIgnoreCase("img") - || exName.equalsIgnoreCase("png") - || exName.equalsIgnoreCase("jpg") - || exName.equalsIgnoreCase("jepg")) { - //fType = new FileType("图片", ) - } else if (exName.equalsIgnoreCase("mp3") || exName.equalsIgnoreCase("wm")) { - //fType = new FileType("音乐", ); - } else if (exName.equalsIgnoreCase("mp4") - || exName.equalsIgnoreCase("rm") - || exName.equalsIgnoreCase("rmvb")) { - //fType = new FileType("视频", ); + public static boolean checkMD5(String md5, InputStream is) { + if (TextUtils.isEmpty(md5) || is == null) { + Log.e(TAG, "MD5 string empty or updateFile null"); + return false; + } + + String calculatedDigest = getFileMD5(is); + if (calculatedDigest == null) { + Log.e(TAG, "calculatedDigest null"); + return false; } - return fType; + return calculatedDigest.equalsIgnoreCase(md5); } /** - * 获取扩展名 + * 获取文件MD5码 */ - public String getExName(String path) { - int separatorIndex = path.lastIndexOf("."); - return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length()); + public static String getFileMD5(File updateFile) { + InputStream is; + try { + is = new FileInputStream(updateFile); + } catch (FileNotFoundException e) { + Log.e(TAG, "Exception while getting FileInputStream", e); + return null; + } + + return getFileMD5(is); } /** - * 获取apk文件的icon - * - * @param path apk文件路径 + * 获取文件MD5码 */ - public Drawable getApkIcon(String path) { - PackageManager pm = mContext.getPackageManager(); - PackageInfo info = pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES); - if (info != null) { - ApplicationInfo appInfo = info.applicationInfo; - //android有bug,需要下面这两句话来修复才能获取apk图片 - appInfo.sourceDir = path; - appInfo.publicSourceDir = path; - // String packageName = appInfo.packageName; //得到安装包名称 - // String version=info.versionName; //得到版本信息 - return pm.getApplicationIcon(appInfo); + public static String getFileMD5(InputStream is) { + MessageDigest digest; + try { + digest = MessageDigest.getInstance("MD5"); + } catch (NoSuchAlgorithmException e) { + Log.e(TAG, "Exception while getting digest", e); + return null; } - return null; - } - class FileType { - String name; - Drawable icon; + byte[] buffer = new byte[8192]; + int read; + try { + while ((read = is.read(buffer)) > 0) { + digest.update(buffer, 0, read); + } + byte[] md5sum = digest.digest(); + BigInteger bigInt = new BigInteger(1, md5sum); + String output = bigInt.toString(16); + // Fill to 32 chars + output = String.format("%32s", output).replace(' ', '0'); + return output; + } catch (IOException e) { + throw new RuntimeException("Unable to process file for MD5", e); + } finally { + try { + is.close(); + } catch (IOException e) { + Log.e(TAG, "Exception on closing MD5 input stream", e); + } + } + } - public FileType(String name, Drawable icon) { - this.name = name; - this.icon = icon; + /** + * 文件列表 + */ + public List loadFiles(String path) { + File file = new File(path); + File[] files = file.listFiles(); + List list = new ArrayList<>(); + for (File f : files) { + FileEntity entity = new FileEntity(); + entity.fileName = f.getName(); + //entity.fileInfo = getFileType(f.getPath()); + //entity.fileDrawable = getApkIcon(mContext, f.getPath()); + list.add(entity); } + return list; } } diff --git a/README.md b/README.md index 3b2b43a2..877197db 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,20 @@ # Aria ![图标](https://github.com/AriaLyy/DownloadUtil/blob/v_2.0/app/src/main/res/mipmap-hdpi/ic_launcher.png)
-Aria,让上传、下载更容易实现
+Aria项目源于15年工作中遇到的一个文件下载管理的需求,当时被下载折磨的痛不欲生,从那时起便萌生了编写一个简单易用,稳当高效的下载框架,aria经历了1.0到3.0的开发,算是越来越接近当初所制定的目标了。 Aria有以下特点: - - 简单 - - 可在Dialog、popupWindow等组件中使用 - - 支持多线程、多任务下载 - - 支持多任务自动调度 - - 可以直接获取速度 - - 支持https地址下载 - - 支持上传操作 + + 简单、方便 + - 可以在Activity、Service、Fragment、Dialog、popupWindow、Notification等组件中使用 + - 支持任务自动调度,使用者不需要关心任务状态切换的逻辑 + - [通过Aria的事件,能很容易获取当前下载任务的下载状态](#二、下载状态获取) + - [一句代码就可以动态设置最大下载数](#通过代码修改Aria参数) + - [一句代码加可以获取当前的下载速度](#其它好用的API) + - [通过修改配置文件很容易就能修改下载线程数](#通过文件修改Aria配置参数) + + 支持https地址下载 + - 在配置文件中很容易就可以设置CA证书的信息 + + 支持300、301、302重定向下载链接下载 + + 支持上传操作 + Aria怎样使用? * [下载](#使用) @@ -20,7 +25,7 @@ Aria怎样使用? ## 下载 [![Download](https://api.bintray.com/packages/arialyy/maven/Aria/images/download.svg)](https://bintray.com/arialyy/maven/Aria/_latestVersion)
```java -compile 'com.arialyy.aria:Aria:3.0.3' +compile 'com.arialyy.aria:Aria:3.1.0' ``` ## 示例 @@ -72,7 +77,8 @@ compile 'com.arialyy.aria:Aria:3.0.3' Aria.download(this).load(DOWNLOAD_URL).cancel(); ``` -### 二、如果你希望读取下载进度或下载信息,那么你需要创建事件类,并在onResume(Activity、Fragment)或构造函数(Dialog、PopupWindow),将该事件类注册到Aria管理器。 +### 二、下载状态获取 +如果你希望读取下载进度或下载信息,那么你需要创建事件类,并在onResume(Activity、Fragment)或构造函数(Dialog、PopupWindow),将该事件类注册到Aria管理器。 * 创建事件类 ```java @@ -104,8 +110,99 @@ compile 'com.arialyy.aria:Aria:3.0.3' } ``` -### 关于下载的其它api -[Download API](https://github.com/AriaLyy/Aria/blob/master/DownloadApi.md) +### 三、Aria参数配置 +#### 通过文件修改Aria配置参数 +创建`aria_config.xml`文件,将其放在`assets`目录下,添加以下内容 +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +#### 通过代码修改Aria参数 +除了文件方式外修改Aria参数外,同样的,你也可以在代码中动态修改Aria参数
+通过`Aria.get(this).getDownloadConfig()`或`Aria.get(this).getUploadConfig()`直接获取配置文件,然后修改参数
+如以下所示: +```java +// 修改最大下载数,调用完成后,立即生效 +// 如当前下载任务数是4,修改完成后,当前任务数会被Aria自动调度任务数 +Aria.get(this).getDownloadConfig().setMaxTaskNum(3); +``` + +### 其它好用的API +* 停止所有任务 + +```java +Aria.download(this).stopAllTask(); +``` +* 删除所有任务 + +```java +Aria.download(this).removeAllTask(); +``` +* 获取当前任务的下载速度 +速度参数有点特殊,需要[下载事件支持](#下载事件监听) +``` java +@Override public void onTaskRunning(DownloadTask task) { + //如果你打开了速度单位转换配置,将可以通过以下方法获取带单位的下载速度,如:1 m/s + String convertSpeed = task.getConvertSpeed(); + //如果你有自己的单位格式,可以通过以下方法获取原始byte长度 + long speed = task.getSpeed(); +} +``` **tips:为了防止内存泄露的情况,事件类需要使用staic进行修饰** @@ -132,9 +229,7 @@ compile 'com.arialyy.aria:Aria:3.0.3' * 取消上传 ```java - Aria.upload(this) - .load(filePath) - .cancel(); + Aria.upload(this).load(filePath).cancel(); ``` ## 其他 @@ -142,7 +237,11 @@ compile 'com.arialyy.aria:Aria:3.0.3' *** +## 后续版本开发规划 +* 实现上传队列调度功能 + ## 开发日志 + + v_3.1.0 添加Aria配置文件,优化代码 + v_3.0.3 修复暂停后删除任务,闪退问题,添加删除记录的api + v_3.0.2 支持30x重定向链接下载 + v_3.0.0 添加上传任务支持,修复一些已发现的bug diff --git a/app/src/main/assets/aria_config.xml b/app/src/main/assets/aria_config.xml index 80d8ded9..f80e558e 100644 --- a/app/src/main/assets/aria_config.xml +++ b/app/src/main/assets/aria_config.xml @@ -1,11 +1,11 @@ - + - - + + @@ -31,6 +31,9 @@ + + +