包含断点续传,以下代码只是核心思路,并不健壮
package com.itheima.mutildownload;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import android.os.Bundle;
import android.os.Environment;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
public class MainActivity extends Activity {
private EditText et_path;
private EditText et_thread_number;
private LinearLayout ll;
private int threadCount; //线程的个数
private static int runningThread; //正在运行的线程
private List<ProgressBar> pbs; //存进度条的引用
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//下载的路径
et_path = (EditText) findViewById(R.id.et_path);
//下载的线程个数
et_thread_number = (EditText) findViewById(R.id.et_thread_number);
//来来存放 进度条
ll = (LinearLayout) findViewById(R.id.ll);
pbs = new ArrayList<ProgressBar>();
}
/**
* 点击 按钮 进行下载的逻辑
* @param v
*/
public void click(View v){
//拿到 下载的路径 和 线程的个数
String path = et_path.getText().toString().trim();
String number = et_thread_number.getText().toString().trim(); //线程的个数
threadCount = Integer.parseInt(number);
ll.removeAllViews();
pbs.clear();
for (int i = 0; i < threadCount; i++) {
//动态的加载进度条
ProgressBar pb = (ProgressBar) View.inflate(getApplicationContext(), R.layout.pb, null);
ll.addView(pb);
pbs.add(pb); //加入集合中
}
//1获取到服务器资源的大小
try {
URL url = new URL(path);
//打开一个url连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置conn 的参数
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
//获取服务器返回的状态码
int code = conn.getResponseCode();
if (code == 200) { //200 请求服务器资源全部返回成功 //206 请求部分服务器资源返回成功
//获取到服务器资源的大小
int length = conn.getContentLength();
runningThread = threadCount;
//2 创建一个大小和服务器一模一样的文件 rw模式
RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path), "rw");
raf.setLength(length);
//每个线程下载的大小是多少
int blockSize = length / threadCount;
for (int i = 0; i < threadCount; i++) {
int startIndex = i*blockSize; //每个线程下载的开启位置
int endIndex = (i+1)*blockSize -1; //每个线程下载的结束位置
//有一种特殊情况 最后一个线程
if (i == threadCount-1) {
endIndex = length - 1;
}
System.out.println("线程id~"+i+"理论下载的位置-"+startIndex+"--"+endIndex);
//3 开启多个线程
DownLoadThread downLoadThread = new DownLoadThread(path, startIndex, endIndex,i);
downLoadThread.start();
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
//这个是我线程真正下载的类
public class DownLoadThread extends Thread{
private String path; //下载路径
private int startIndex;
private int endIndex;
private int threadId;
private int pbmaxprogress;
private int lastdownLoadSize; //上一次下载的大小
public DownLoadThread(String path,int startIndex,int endIndex, int threadId){
this.path = path;
this.startIndex = startIndex;
this.endIndex = endIndex;
this.threadId = threadId;
}
@Override
public void run() {
try {
pbmaxprogress = endIndex - startIndex;
URL url = new URL(path);
//打开一个url连接
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
//设置conn 的参数
conn.setRequestMethod("GET");
conn.setConnectTimeout(5000);
//判断一下 是否存在下载记录
File file = new File(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path)+threadId+".txt");
if (file.exists() && file.length()>0) {
//说明已经下载过
FileInputStream fis = new FileInputStream(file);
BufferedReader bufr = new BufferedReader(new InputStreamReader(fis));
String lastPosition = bufr.readLine(); //上次我保存的位置
//从lastPosition 位置开始
conn.setRequestProperty("Range", "bytes="+lastPosition+"-"+endIndex);
//上次下载的大小
lastdownLoadSize = Integer.parseInt(lastPosition)- startIndex;
//要改变一下 startindex的位置
startIndex = Integer.parseInt(lastPosition);
fis.close();
System.out.println("线程id~"+threadId+"真实下载的位置-"+startIndex+"--"+endIndex);
}else {
//开多个线程去下载 设置一个头信息 Range 去服务器 取部分数据 从startIndex 开启取 取到 endIndex结束
conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
}
//获取服务器返回的状态码
int code = conn.getResponseCode();
if (code == 206) { //200 请求服务器资源全部返回成功 //206 请求部分服务器资源返回成功
InputStream inputStream = conn.getInputStream(); //获取服务器返回的数据
RandomAccessFile raf = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path), "rw");
raf.seek(startIndex); //设置指针偏移量 从 startindex 位置开始读
int len = -1;
byte buffer[] = new byte[1024*1024];
//做断点续传 首先我们要把每个线程 下载的位置 存起来
int total = 0;
while((len=inputStream.read(buffer))!=-1){
raf.write(buffer, 0, len);
total+=len; //当前线程下载的总大小
int currentThreadPosition = startIndex + total; //把当前线程下载的位置给保存起来
//怎么保存 保存到哪里
RandomAccessFile raff = new RandomAccessFile(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path)+threadId+".txt", "rwd");
raff.write(String.valueOf(currentThreadPosition).getBytes());
raff.close();
// 更新进度条
pbs.get(threadId).setMax(pbmaxprogress); //设置进度条的最大值
pbs.get(threadId).setProgress(lastdownLoadSize+total); //设置当前的进度条的进度
}
raf.close();
inputStream.close();
//说明 所有的线程都下载完毕了
System.out.println("线程id~"+threadId+"下载ok");
synchronized (DownLoadThread.class) {
runningThread--;
if (runningThread <= 0) {
// 说明所有的线程都下载完毕了
for (int i = 0; i < threadCount; i++) {
File deleteFile = new File(Environment.getExternalStorageDirectory().getPath()+"/"+getFileName(path)+i+".txt");
deleteFile.delete();
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
super.run();
}
}
//获取路径的名称
public static String getFileName(String path){
int start = path.lastIndexOf("/")+1;
return path.substring(start);
}
}