接着第一篇的后面,上次是实现了断点续传的功能,下载的时候能够暂停,程序退出的时候,会记录下载的断点位置,下次再进行下载的时候会接着上次没有下载完成的地方下载。
这一篇在原来断点续传的基础上加入多线程下载的功能。多线程下载,就是把一个下载任务原先是一个子线程完成下载的。现在把这个下载任务分配给多个子线程来下载,已达到占用较多的带宽来下载资源的目的。
1、首先得到下载的文件的大小,然后根据下载的子线程数来分配每个线程负责下载的部分
2、将每个子线程的负责下载的位置,即startPos和endPos都分配好之后,保存到数据库中
3、从容器中把每个线程拿出来,然后创建下载任务,开始下载
4、下载的时候,HttpURLConnection的setRequestProperty()方法注意请求得到的文件长度为该线程之前分配好的文件长度
5、下载中,同断点续传一样,一边下载时,一边将每个线程的下载进度保存到数据库中
部分代码:
@Override
protected List<DownloadInfo> doInBackground(String... args) {
String urlStr = args[0];
infos = DownloadDao.getInstance(context).getDownloadInfos(urlStr);
if (infos == null || infos.isEmpty()) {
try {
URL url = new URL(args[0]);
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setReadTimeout(5000);
conn.setRequestMethod("GET");
fileSize = conn.getContentLength();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
int range = fileSize / threadCount;
for (int i = 0; i < threadCount - 1; i++) {
DownloadInfo info = new DownloadInfo(fileSize, 0, urlStr, i
* range, (i + 1) * range - 1, i);
infos.add(info);
}
DownloadInfo info = new DownloadInfo(fileSize, 0, urlStr, fileSize
- range, fileSize, threadCount - 1);
infos.add(info);
DownloadDao.getInstance(context).saveDownloadInfos(infos);
return infos;
}
return infos;
}
@Override
protected void onPostExecute(List<DownloadInfo> infos) {
super.onPostExecute(infos);
if (infos == null && infos.isEmpty()) {
return;
}
int progress = getProgress(infos);
getFileSize(infos);
callback.setProgress(progress,fileSize);
DownloadTask task = new DownloadTask(context, handler,fileSize);
task.STATE = DownloadTask.DOWNLOADING;
task.download(infos);
}
DownloadTask:
package com.shulf.downloadtest;
import java.io.File;
import java.io.FileNotFoundException;
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.List;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
/**
* 下载线程类,得到下载实体中的信息,开启线程进行下载
*
* @author Administrator
*
*/
public class DownloadTask{
private Handler handler;
private Context context;
/*
* 下载的文件大小
*/
private int fileSize;
/*
* 整个文件下载的完成度
*/
private int mComplete = 0;
/*
* 下载状态
*/
public static int DOWNLOADING = 1;
/*
* 暂停状态
*/
public static int PAUSE = 2;
public static int STATE = DOWNLOADING;// 1表示未下载状态,2表示暂停状态
public DownloadTask(Context context, Handler handler,int fileSize) {
this.fileSize = fileSize;
this.context = context;
this.handler = handler;
}
/**
* 得到下载的所有下载实体(所有线程)
* @param infos
*/
public void download(List<DownloadInfo> infos) {
for (int i = 0; i < infos.size(); i++) {
DownloadInfo info = infos.get(i);
new DownloadThread(info).start();
}
}
/**
* 开启线程正式下载
* @author Administrator
*
*/
private class DownloadThread extends Thread {
private DownloadInfo info;
public DownloadThread(DownloadInfo info) {
this.info = info;
}
@Override
public void run() {
HttpURLConnection conn = null;
InputStream in = null;
RandomAccessFile randomAccessFile = null;
File saveFile = new File("/mnt/sdcard/", "test.apk");
int completeSize = info.completeSize;
try {
URL url = new URL(info.url);
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
/** 设置请求头的属性,从断点处开始到文件的长度 */
conn.setRequestProperty("Range", "bytes="
+ (info.startPos + completeSize) + "-" + info.endPos);
randomAccessFile = new RandomAccessFile(saveFile, "rwd");
randomAccessFile.seek(info.startPos + completeSize);
in = conn.getInputStream();
byte[] buffer = new byte[4096];
int length = -1;
while ((length = in.read(buffer)) != -1) {
randomAccessFile.write(buffer, 0, length);
completeSize += length;
DownloadDao.getInstance(context).updateComplete(
info.threadId, info.url, completeSize);
Message msg = Message.obtain();
msg.what = 1;
msg.arg1 = length;
msg.arg2 =fileSize;
handler.sendMessage(msg);
if (STATE == PAUSE) {
return;
}
}
} catch (ProtocolException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (in != null) {
in.close();
}
if (randomAccessFile != null) {
randomAccessFile.close();
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}