Skip to content

Commit 933943f

Browse files
author
zhangchi
committed
Bugfix:修改多次触发任务时的并发问题,防止同时触发多个相同的下载任务;修改任务队列为线程安全模式;
* 修改多线程任务的线程数量设置机制,每个任务可以自定义设置下载线程数量;通过同构方法dlStart(String url, String dirPath, DLTaskListener listener,int threadNum); * 添加日志开关及日志记录,开关方法为setDebugEnable,日志TAG为DLManager;方便调试;
1 parent b378ad1 commit 933943f

File tree

2 files changed

+96
-14
lines changed

2 files changed

+96
-14
lines changed

Downloader/src/main/java/cn/aigestudio/downloader/bizs/DLManager.java

+90-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package cn.aigestudio.downloader.bizs;
22

33
import android.content.Context;
4+
import android.util.Log;
45

56
import org.apache.http.HttpStatus;
67

@@ -9,9 +10,9 @@
910
import java.io.InputStream;
1011
import java.io.RandomAccessFile;
1112
import java.net.HttpURLConnection;
12-
import java.util.Hashtable;
1313
import java.util.List;
1414
import java.util.UUID;
15+
import java.util.concurrent.ConcurrentHashMap;
1516
import java.util.concurrent.ExecutorService;
1617
import java.util.concurrent.Executors;
1718

@@ -52,6 +53,10 @@
5253
* 修改域名重定向后无法暂停问题
5354
* Bugfix:can not start multi-threads to download file when we in url redirection.
5455
* Bugfix:can not stop a download task when we in url redirection.
56+
* @author zhangchi 2015-10-13
57+
* Bugfix:修改多次触发任务时的并发问题,防止同时触发多个相同的下载任务;修改任务队列为线程安全模式;
58+
* 修改多线程任务的线程数量设置机制,每个任务可以自定义设置下载线程数量;通过同构方法dlStart(String url, String dirPath, DLTaskListener listener,int threadNum);
59+
* 添加日志开关及日志记录,开关方法为setDebugEnable,日志TAG为DLManager;方便调试;
5560
*/
5661
public final class DLManager {
5762
private static final int THREAD_POOL_SIZE = 32;
@@ -61,7 +66,7 @@ public final class DLManager {
6166
/**
6267
* 任务列表
6368
*/
64-
private static Hashtable<String, DLTask> sTaskDLing;
69+
private static ConcurrentHashMap<String, DLTask> sTaskDLing;
6570

6671

6772
private ExecutorService mExecutor;
@@ -71,7 +76,7 @@ public DLManager(Context context) {
7176
this.context = context;
7277
this.mExecutor = Executors.newFixedThreadPool(THREAD_POOL_SIZE);
7378
sDBManager = DBManager.getInstance(context);
74-
sTaskDLing = new Hashtable<>();
79+
sTaskDLing = new ConcurrentHashMap<String, DLTask>();
7580
}
7681

7782
public static DLManager getInstance(Context context) {
@@ -86,6 +91,19 @@ public void dlStart(String url, String dirPath, DLTaskListener listener) {
8691
mExecutor.execute(dlPrepare);
8792
}
8893

94+
/**
95+
* 开启下载任务,threadNum为如支持多线程下载时的线程数量(默认为3个);
96+
*
97+
* @param url
98+
* @param dirPath
99+
* @param listener
100+
* @param threadNum
101+
*/
102+
public void dlStart(String url, String dirPath, DLTaskListener listener,int threadNum) {
103+
DLPrepare dlPrepare = new DLPrepare(url, dirPath, listener,threadNum);
104+
mExecutor.execute(dlPrepare);
105+
}
106+
89107
public void dlStop(String url) {
90108
if (sTaskDLing.containsKey(url)) {
91109
DLTask task = sTaskDLing.get(url);
@@ -116,6 +134,14 @@ public void dlCancel(String url) {
116134
private class DLPrepare implements Runnable {
117135
private String url, dirPath;// 下载路径和保存目录
118136
private DLTaskListener listener;// 下载监听器
137+
private int threadNum = defaultThreadNumberSingleTask;
138+
139+
private DLPrepare(String url, String dirPath, DLTaskListener listener,int threadNum) {
140+
this.url = url;
141+
this.dirPath = dirPath;
142+
this.listener = listener;
143+
this.threadNum = threadNum;
144+
}
119145

120146
private DLPrepare(String url, String dirPath, DLTaskListener listener) {
121147
this.url = url;
@@ -137,9 +163,7 @@ public void run() {
137163
}
138164
synchronized (sTaskDLing){//fix: 如果文件正在取消或异常,这里不能立即重新开始,表现为当多次点击下载时:1. 同时引发多个任务下载;2. 点击无效且无任何返回值;需要进行并发线程的业务处理;
139165
// 如果文件正在下载
140-
// DLTask dlTask = sTaskDLing.get(url);
141-
// if (dlTask!=null&&(!dlTask.isStop)) {
142-
if (sTaskDLing.contains(url)) {
166+
if (sTaskDLing.containsKey(url)) {
143167
// 文件正在下载 File is downloading
144168
if(listener!=null)listener.onError(ERROR_DOWNLOADING);
145169
} else {
@@ -148,7 +172,7 @@ public void run() {
148172
if (null != listener) listener.onStart(fileName, realUrl);
149173
File file = new File(dirPath, fileName);
150174
if (null == info || !file.exists()) {
151-
info = new TaskInfo(FileUtil.createFile(dirPath, fileName), url, realUrl, 0, 0);
175+
info = new TaskInfo(FileUtil.createFile(dirPath, fileName), url, realUrl, 0, 0,threadNum);
152176
}
153177
DLTask task = new DLTask(info, listener);
154178
sTaskDLing.put(info.baseUrl, task);
@@ -224,6 +248,9 @@ public void run() {
224248
conn = NetUtil.buildConnection(info.realUrl);
225249
conn.setRequestProperty("Range", "bytes=" + 0 + "-" + Integer.MAX_VALUE);
226250
if (conn.getResponseCode() == HttpStatus.SC_PARTIAL_CONTENT) {
251+
if(isDebug){
252+
Log.d(TAG,"DLTask has 206 ,url:"+info.baseUrl);
253+
}
227254
fileLength = conn.getContentLength();
228255
if (info.dlLocalFile.exists() && info.dlLocalFile.length() == fileLength) {
229256
isExists = true;
@@ -235,13 +262,19 @@ public void run() {
235262
sDBManager.insertTaskInfo(info);
236263
int threadSize;
237264
int length = LENGTH_PER_THREAD;
238-
if (fileLength <= LENGTH_PER_THREAD) {
239-
threadSize = 3;
240-
length = fileLength / threadSize;
241-
} else {
242-
threadSize = fileLength / LENGTH_PER_THREAD;
243-
}
265+
// if (fileLength <= LENGTH_PER_THREAD) {
266+
// threadSize = 3;
267+
// length = fileLength / threadSize;
268+
// } else {
269+
// threadSize = fileLength / LENGTH_PER_THREAD;
270+
// }
271+
//不建议设定过多线程,根据手机硬件及系统调度特定,最好和cpu核数匹配;
272+
threadSize = info.threadNum;
273+
length = fileLength / threadSize;
244274
int remainder = fileLength % length;
275+
if(isDebug){
276+
Log.d(TAG,"DLTask has multiThread begin,threadSize:"+threadSize+";prelength:"+length+" ;url:"+info.baseUrl);
277+
}
245278
for (int i = 0; i < threadSize; i++) {
246279
int start = i * length;
247280
int end = start + length - 1;
@@ -256,6 +289,9 @@ public void run() {
256289
}
257290
}
258291
} else if (conn.getResponseCode() == HttpStatus.SC_OK) {
292+
if(isDebug){
293+
Log.d(TAG,"DLTask has 200 ,url:"+info.baseUrl);
294+
}
259295
fileLength = conn.getContentLength();
260296
if (info.dlLocalFile.exists() && info.dlLocalFile.length() == fileLength) {
261297
sTaskDLing.remove(info.baseUrl);
@@ -272,6 +308,10 @@ public void run() {
272308
sDBManager.updateTaskInfo(info);
273309
sTaskDLing.remove(info.baseUrl);
274310
}
311+
if(isDebug){
312+
Log.e(TAG, "DLTask running error:"+e+",url:" + info.baseUrl);
313+
e.printStackTrace();
314+
}
275315
if (null != mListener) mListener.onError(e.getMessage());
276316
} finally {
277317
if (conn != null) {
@@ -282,6 +322,9 @@ public void run() {
282322
}else{
283323
//下载失败:网络异常
284324
sTaskDLing.remove(info.baseUrl);
325+
if(isDebug){
326+
Log.e(TAG,"DLTask no network error ,url:"+info.baseUrl);
327+
}
285328
if (null != mListener) mListener.onError(ERROR_NO_NETWORK);
286329
}
287330
}
@@ -331,6 +374,9 @@ public void run() {
331374
raf = new RandomAccessFile(info.dlLocalFile,
332375
PublicCons.AccessModes.ACCESS_MODE_RWD);
333376
if (conn.getResponseCode() == HttpStatus.SC_PARTIAL_CONTENT) {
377+
if(isDebug){
378+
Log.d(TAG,"DLThread has 206 ,url:"+info.baseUrl);
379+
}
334380
if (!isResume) {
335381
sDBManager.insertThreadInfo(info);
336382
}
@@ -352,6 +398,9 @@ public void run() {
352398
sDBManager.updateThreadInfo(info);
353399
}
354400
} else if (conn.getResponseCode() == HttpStatus.SC_OK) {
401+
if(isDebug){
402+
Log.d(TAG,"DLThread has 200 ,url:"+info.baseUrl);
403+
}
355404
is = conn.getInputStream();
356405
raf.seek(info.start);
357406
byte[] b = new byte[1024];
@@ -365,6 +414,10 @@ public void run() {
365414
if (null != sDBManager.queryThreadInfoById(info.id)) {
366415
info.start = info.start + progress;
367416
sDBManager.updateThreadInfo(info);
417+
if(isDebug){
418+
Log.e(TAG,"DLThread 's running error:"+e);
419+
e.printStackTrace();
420+
}
368421
}
369422
} finally {
370423
try {
@@ -384,4 +437,28 @@ public void run() {
384437
}
385438
}
386439
}
440+
441+
/**
442+
* 调试日志开关,
443+
*
444+
* tag为 DLManager
445+
*
446+
* @param debugEnable
447+
*/
448+
public void setDebugEnable(boolean debugEnable){
449+
isDebug = debugEnable;
450+
}
451+
452+
//调试日志开关
453+
454+
private boolean isDebug = false;
455+
456+
private static final String TAG = DLManager.class.getSimpleName();
457+
458+
private int defaultThreadNumberSingleTask = 3;
459+
460+
public void setDefaultThreadNum(int threadNumberSingleTask){
461+
this.defaultThreadNumberSingleTask = threadNumberSingleTask;
462+
}
463+
387464
}

Downloader/src/main/java/cn/aigestudio/downloader/entities/TaskInfo.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@
1212
* 修改构造方法
1313
*/
1414
public class TaskInfo extends DLInfo implements Serializable {
15-
public int progress, length;
15+
public int progress, length,threadNum;
1616

1717
public TaskInfo(File dlLocalFile, String baseUrl, String realUrl, int progress, int length) {
18+
this(dlLocalFile, baseUrl, realUrl, progress,length,3);
19+
}
20+
21+
public TaskInfo(File dlLocalFile, String baseUrl, String realUrl, int progress, int length, int threadNum) {
1822
super(dlLocalFile, baseUrl, realUrl);
1923
this.progress = progress;
2024
this.length = length;
25+
this.threadNum = threadNum;
2126
}
2227
}

0 commit comments

Comments
 (0)