## 多线程下载其实哪里都在用,因此API都是JAVA的API,和Android关系不大 ##
- 请求文件长度
- 创建本地文件
String path = "www.baidu.com/xxx.jpg";
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setReadTimeout(5000);
conn.setConnectTimeout(5000);
if(conn.getResponseCode()==200){
int length = conn.getContentLength();
// 创建本地文件
File file = new File("xxx.jpg");
//随机读写,rw可读可写,d实时刷新内存数据到磁盘
RandomAccessFile raf = new RandomAccessFile(file, "rwd");
raf.setLength(length);
raf.close();
//threadCount为自定义的多线程下载的线程数
int size = length/threadCount;
// 计算每个线程的起始结束下载位置
for(int i=0; i<threadCount; i++){
int startIdx = i*size;
int endIdx = (i+1)*size-1;
if (i==threadCount-1){
endIdx = length-1; //可能除不尽
}
//启动线程开始下载,构造入参分别是线程ID,起始结束位置
new DownLoadThread(threadId, startIdx, endIdx).start();
}
}
- 线程下载
- 断点续传
public DownLoadThread extends Thread{
int startIdx;
int endIdx;
int threadId;
/*构造函数.....*/
public void run(){
//断点续传,读取上次下载的结束位置
File file = new File(ThreadIdx+".txt");
if (file.exists()){
FileInputStream fis = new FileInputStream(file);
//存都是按照byte存储的,因此取出来要转为换char
BufferedReader br = new BufferedReader(new InputStreamReader(fis));
startIdx = Integer.parseInt(br.readLine());
fis.close();
}
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection)url.openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
conn.setReadTimeout(5000);
conn.setRequestProperty("Range","bytes="+startIdx+"-"+endIdx);
if (conn.getResponseCode()==206){//部分数据返回是206
InputStream is = conn.getInputStream();
bytes[] b = new bytes[1024];
int len = 0;
int total = startIdx;
File file = new File("xxx.jpg");
RandomAccessFile raf = newRandomAccessFile(file, "rwd");
raf.seek(startIdx);//设置起始位置
while((len=is.read(b))!=-1){
raf.write(b, 0, len);
total += len;
File progressFile = newFile(threadId+".txt");
RandomAccessFile praf = new RandomAccessFile(processFile, "rwd");//实时写入
praf.write((total+"").getBytes());//每次都覆盖
praf.close();//文件中数字可能差一个1024字节,临时文件一定要在raf.write后面
}
raf.close();
//删除praf不能直接删除文件,可能存在一个线程完了其他线程没有结束,下次再次下载
synchronized(){
if (/*所有线程都ok*/){
//删除所有临时文件
}
}
}
}
}
- 界面通过ProgressBar显示进度
- 样式显示水平进度条
<ProgressBar
android:id="@+id/pb"
style="@android:style/Widget.ProgressBar.Horizontal"
/>
- 设置ProcessBar的显示
//进图条最大值就是设置为源文件的长度
pb.setMax(conn.getContentLength());
//pb有特殊处理可以直接在子线程刷新UI
int progress;//设置个全局的进度字段,每个线程加上当前下载的长度
pb.setProcess(progress);//注意线程安全问题,synchronized
//断点续传时候,也要设置进度条,初始值也给进度条
//如果要显示数字进度,必须用long类型,不然会导致整形溢出
(long)pb.getProcess()*100/pb.getMax()+"%"
//数字进度(TextView)可能存在到99的情况,此时文件已经下完,强制刷新到100
xUtils
- 很明显这个功能是通用方法
- xUtils包含多线程断点续传
- 工具依然在gitHub上
public void click(View v){
HttpUtils utils = new HttpUtils();
String url = "www.baidu.com/xxx.jpg"
utils.download(url, "sdcard/xxx.jpg", true/*断点续传*/,true/*响应头返回文件名则重命名*/,new RequestCallBack<File>(){
public void onSuccess(ResponseInfo<File> ri){
//下载成功调用
}
public void onFailure(HttpException args, String reason){
//下载失败调用,reason返回失败原因
}
public void onLoading(long total, long current, boolean isUploading){
//中间刷新进度条什么的
}
});
}