1
1
package cn .aigestudio .downloader .bizs ;
2
2
3
3
import android .content .Context ;
4
+ import android .util .Log ;
4
5
5
6
import org .apache .http .HttpStatus ;
6
7
9
10
import java .io .InputStream ;
10
11
import java .io .RandomAccessFile ;
11
12
import java .net .HttpURLConnection ;
12
- import java .util .Hashtable ;
13
13
import java .util .List ;
14
14
import java .util .UUID ;
15
+ import java .util .concurrent .ConcurrentHashMap ;
15
16
import java .util .concurrent .ExecutorService ;
16
17
import java .util .concurrent .Executors ;
17
18
52
53
* 修改域名重定向后无法暂停问题
53
54
* Bugfix:can not start multi-threads to download file when we in url redirection.
54
55
* 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;方便调试;
55
60
*/
56
61
public final class DLManager {
57
62
private static final int THREAD_POOL_SIZE = 32 ;
@@ -61,7 +66,7 @@ public final class DLManager {
61
66
/**
62
67
* 任务列表
63
68
*/
64
- private static Hashtable <String , DLTask > sTaskDLing ;
69
+ private static ConcurrentHashMap <String , DLTask > sTaskDLing ;
65
70
66
71
67
72
private ExecutorService mExecutor ;
@@ -71,7 +76,7 @@ public DLManager(Context context) {
71
76
this .context = context ;
72
77
this .mExecutor = Executors .newFixedThreadPool (THREAD_POOL_SIZE );
73
78
sDBManager = DBManager .getInstance (context );
74
- sTaskDLing = new Hashtable < >();
79
+ sTaskDLing = new ConcurrentHashMap < String , DLTask >();
75
80
}
76
81
77
82
public static DLManager getInstance (Context context ) {
@@ -86,6 +91,19 @@ public void dlStart(String url, String dirPath, DLTaskListener listener) {
86
91
mExecutor .execute (dlPrepare );
87
92
}
88
93
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
+
89
107
public void dlStop (String url ) {
90
108
if (sTaskDLing .containsKey (url )) {
91
109
DLTask task = sTaskDLing .get (url );
@@ -116,6 +134,14 @@ public void dlCancel(String url) {
116
134
private class DLPrepare implements Runnable {
117
135
private String url , dirPath ;// 下载路径和保存目录
118
136
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
+ }
119
145
120
146
private DLPrepare (String url , String dirPath , DLTaskListener listener ) {
121
147
this .url = url ;
@@ -137,9 +163,7 @@ public void run() {
137
163
}
138
164
synchronized (sTaskDLing ){//fix: 如果文件正在取消或异常,这里不能立即重新开始,表现为当多次点击下载时:1. 同时引发多个任务下载;2. 点击无效且无任何返回值;需要进行并发线程的业务处理;
139
165
// 如果文件正在下载
140
- // DLTask dlTask = sTaskDLing.get(url);
141
- // if (dlTask!=null&&(!dlTask.isStop)) {
142
- if (sTaskDLing .contains (url )) {
166
+ if (sTaskDLing .containsKey (url )) {
143
167
// 文件正在下载 File is downloading
144
168
if (listener !=null )listener .onError (ERROR_DOWNLOADING );
145
169
} else {
@@ -148,7 +172,7 @@ public void run() {
148
172
if (null != listener ) listener .onStart (fileName , realUrl );
149
173
File file = new File (dirPath , fileName );
150
174
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 );
152
176
}
153
177
DLTask task = new DLTask (info , listener );
154
178
sTaskDLing .put (info .baseUrl , task );
@@ -224,6 +248,9 @@ public void run() {
224
248
conn = NetUtil .buildConnection (info .realUrl );
225
249
conn .setRequestProperty ("Range" , "bytes=" + 0 + "-" + Integer .MAX_VALUE );
226
250
if (conn .getResponseCode () == HttpStatus .SC_PARTIAL_CONTENT ) {
251
+ if (isDebug ){
252
+ Log .d (TAG ,"DLTask has 206 ,url:" +info .baseUrl );
253
+ }
227
254
fileLength = conn .getContentLength ();
228
255
if (info .dlLocalFile .exists () && info .dlLocalFile .length () == fileLength ) {
229
256
isExists = true ;
@@ -235,13 +262,19 @@ public void run() {
235
262
sDBManager .insertTaskInfo (info );
236
263
int threadSize ;
237
264
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 ;
244
274
int remainder = fileLength % length ;
275
+ if (isDebug ){
276
+ Log .d (TAG ,"DLTask has multiThread begin,threadSize:" +threadSize +";prelength:" +length +" ;url:" +info .baseUrl );
277
+ }
245
278
for (int i = 0 ; i < threadSize ; i ++) {
246
279
int start = i * length ;
247
280
int end = start + length - 1 ;
@@ -256,6 +289,9 @@ public void run() {
256
289
}
257
290
}
258
291
} else if (conn .getResponseCode () == HttpStatus .SC_OK ) {
292
+ if (isDebug ){
293
+ Log .d (TAG ,"DLTask has 200 ,url:" +info .baseUrl );
294
+ }
259
295
fileLength = conn .getContentLength ();
260
296
if (info .dlLocalFile .exists () && info .dlLocalFile .length () == fileLength ) {
261
297
sTaskDLing .remove (info .baseUrl );
@@ -272,6 +308,10 @@ public void run() {
272
308
sDBManager .updateTaskInfo (info );
273
309
sTaskDLing .remove (info .baseUrl );
274
310
}
311
+ if (isDebug ){
312
+ Log .e (TAG , "DLTask running error:" +e +",url:" + info .baseUrl );
313
+ e .printStackTrace ();
314
+ }
275
315
if (null != mListener ) mListener .onError (e .getMessage ());
276
316
} finally {
277
317
if (conn != null ) {
@@ -282,6 +322,9 @@ public void run() {
282
322
}else {
283
323
//下载失败:网络异常
284
324
sTaskDLing .remove (info .baseUrl );
325
+ if (isDebug ){
326
+ Log .e (TAG ,"DLTask no network error ,url:" +info .baseUrl );
327
+ }
285
328
if (null != mListener ) mListener .onError (ERROR_NO_NETWORK );
286
329
}
287
330
}
@@ -331,6 +374,9 @@ public void run() {
331
374
raf = new RandomAccessFile (info .dlLocalFile ,
332
375
PublicCons .AccessModes .ACCESS_MODE_RWD );
333
376
if (conn .getResponseCode () == HttpStatus .SC_PARTIAL_CONTENT ) {
377
+ if (isDebug ){
378
+ Log .d (TAG ,"DLThread has 206 ,url:" +info .baseUrl );
379
+ }
334
380
if (!isResume ) {
335
381
sDBManager .insertThreadInfo (info );
336
382
}
@@ -352,6 +398,9 @@ public void run() {
352
398
sDBManager .updateThreadInfo (info );
353
399
}
354
400
} else if (conn .getResponseCode () == HttpStatus .SC_OK ) {
401
+ if (isDebug ){
402
+ Log .d (TAG ,"DLThread has 200 ,url:" +info .baseUrl );
403
+ }
355
404
is = conn .getInputStream ();
356
405
raf .seek (info .start );
357
406
byte [] b = new byte [1024 ];
@@ -365,6 +414,10 @@ public void run() {
365
414
if (null != sDBManager .queryThreadInfoById (info .id )) {
366
415
info .start = info .start + progress ;
367
416
sDBManager .updateThreadInfo (info );
417
+ if (isDebug ){
418
+ Log .e (TAG ,"DLThread 's running error:" +e );
419
+ e .printStackTrace ();
420
+ }
368
421
}
369
422
} finally {
370
423
try {
@@ -384,4 +437,28 @@ public void run() {
384
437
}
385
438
}
386
439
}
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
+
387
464
}
0 commit comments