package com.example.download;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import android.content.Context;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import com.example.database.DownloadDb;
import com.example.domain.Info;
public class Download {
private int done;
private DownloadDb dao;
private int fileLen;
private Handler handler;
private boolean isPause;
private boolean isDelete;
public Download(Context context, Handler handler) {
dao = new DownloadDb(context);
this.handler = handler;
// 创建目录
// 初始化默认存储文件夹
File file = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/" + "DreamDownload/");
file.mkdir();
}
/**
* 多线程下载
*
* @param path
* 下载路径
* @param thCount
* 需要开启多少个线程
* @throws Exception
*/
public void download(String path, int thCount) throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
// 设置超时时间
conn.setConnectTimeout(5000);
int code = conn.getResponseCode();
if (code == 200) {
fileLen = conn.getContentLength();
String name = path.substring(path.lastIndexOf("/") + 1);
File file = new File(Environment.getExternalStorageDirectory()
.getAbsolutePath() + "/" + "DreamDownload/", name);
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.setLength(fileLen);
raf.close();
// Handler发送消息,主线程接收消息,获取数据的长度
Message msg = new Message();
msg.what = 0;
msg.getData().putInt("fileLen", fileLen);
handler.sendMessage(msg);
// 计算每个线程下载的字节数
int partLen = (fileLen + thCount - 1) / thCount;
for (int i = 0; i < thCount; i++)
new DownloadThread(url, file, partLen, i).start();
} else {
throw new IllegalArgumentException("404 path: " + path);
}
}
private final class DownloadThread extends Thread {
private URL url;
private File file;
private int partLen;
private int id;
public DownloadThread(URL url, File file, int partLen, int id) {
this.url = url;
this.file = file;
this.partLen = partLen;
this.id = id;
}
/**
* 写入操作
*/
public void run() {
// 判断上次是否有未完成任务
Info info = dao.query(url.toString(), id);
if (info != null) {
// 如果有, 读取当前线程已下载量
done += info.getDone();
} else {
// 如果没有, 则创建一个新记录存入
info = new Info(url.toString(), id, 0);
dao.insert(info);
}
int start = id * partLen + info.getDone(); // 开始位置 += 已下载量
int end = (id + 1) * partLen - 1;
try {
HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setReadTimeout(3000);
// 获取指定位置的数据,Range范围如果超出服务器上数据范围, 会以服务器数据末尾为准
conn.setRequestProperty("Range", "bytes=" + start + "-" + end);
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.seek(start);
// 开始读写数据
InputStream in = conn.getInputStream();
byte[] buf = new byte[1024 * 10];
int len;
while ((len = in.read(buf)) != -1) {
//删除
if(isDelete)
{
break;
}
//暂停
if (isPause) {
// 使用线程锁锁定该线程
synchronized (dao) {
try {
dao.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
raf.write(buf, 0, len);
done += len;
info.setDone(info.getDone() + len);
// 记录每个线程已下载的数据量
dao.update(info);
// 新线程中用Handler发送消息,主线程接收消息
Message msg = new Message();
msg.what = 1;
msg.getData().putInt("done", done);
handler.sendMessage(msg);
}
in.close();
raf.close();
// 删除下载记录
dao.deleteAll(info.getPath(), fileLen);
} catch (IOException e) {
e.printStackTrace();
}
}
}
// 暂停下载
public void pause() {
isPause = true;
}
// 继续下载
public void resume() {
isPause = false;
// 恢复所有线程
synchronized (dao) {
dao.notifyAll();
}
}
//删除下载
public void delete(){
isDelete=true;
}
}