安卓笔记4--多线程断点续传
多线程断点续传无论在什么平台上都是极为重要的,这部分知识非常重要。老规矩,用一张图来介绍今天的内容。
图片看不清的话可以右键新窗口打开
直接看代码吧
public class MainActivity extends Activity { String path = "http://192.168.15.77:8080/QQPlayer.exe"; int threadCount = 3; int finishedThreadCount = 0; int currentPbProgress; private ProgressBar pb; private TextView tv; Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { tv.setText((long)pb.getProgress() * 100 / pb.getMax() + "%"); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //进度条用于显示当前下载进度,下载的总字节数作为progress,目标文件的总大小作为max pb = (ProgressBar) findViewById(R.id.pb); tv = (TextView) findViewById(R.id.tv); } public void click(View v){ Thread t = new Thread(){ @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(8000); conn.setReadTimeout(8000); if(conn.getResponseCode() == 200){ //拿到要下载的文件的总长度 int length = conn.getContentLength(); //在本地生成一个临时文件,临时文件大小与目标文件大小一致 File file= new File(Environment.getExternalStorageDirectory(), getFileName(path)); RandomAccessFile raf = new RandomAccessFile(file, "rwd"); raf.setLength(length); raf.close(); //设置进度条的总进度为目标文件总长 pb.setMax(length); //计算每条线程要下载的长度 int size = length / threadCount; //计算每条线程的开始位置与结束位置 for(int i = 0; i < threadCount; i++){ int startIndex = i * size; int endIndex = (i + 1) * size - 1; if( i == threadCount - 1) endIndex = length - 1; // System.out.println("线程" + i + "的下载区间为:" + startIndex + "~" + endIndex); new DownLoadThread(startIndex, endIndex, i).start(); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; t.start(); } String getFileName(String path){ int index = path.lastIndexOf("/"); return path.substring(index + 1); } class DownLoadThread extends Thread{ int startIndex; int endIndex; int threadId; public DownLoadThread(int startIndex, int endIndex, int threadId) { super(); this.startIndex = startIndex; this.endIndex = endIndex; this.threadId = threadId; } @Override public void run() { //开启子线程下载目标文件 try { File fileProgess = new File(Environment.getExternalStorageDirectory(), threadId + ".txt"); int lastTotal = 0; //判断文本临时文件是否存在 if(fileProgess.exists()){ FileInputStream fis = new FileInputStream(fileProgess); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); //获取上一下载的进度 lastTotal = Integer.parseInt(br.readLine()); //改变下载的开始位置,已经下载过的数据,就不要再去请求了 startIndex += lastTotal; fis.close(); //把上一次下载的总进度写入进度条 currentPbProgress += lastTotal; pb.setProgress(currentPbProgress); handler.sendEmptyMessage(0); } System.out.println("线程" + threadId + "的最终下载区间为:" + startIndex + "~" + endIndex); URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); conn.setConnectTimeout(8000); conn.setReadTimeout(8000); //定义请求的数据的范围 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); if(conn.getResponseCode() == 206){ //流里的数据只有startIndex到endIndex区间的数据,并不会包含目标文件所有数据 InputStream is = conn.getInputStream(); byte[] b = new byte[1024]; int len; int total = lastTotal; File file= new File(Environment.getExternalStorageDirectory(), getFileName(path)); RandomAccessFile raf = new RandomAccessFile(file, "rwd"); //改变往raf中写入数据的开始位置 raf.seek(startIndex); while((len = is.read(b)) != -1){ total += len; System.out.println("线程" + threadId + "已下载的字节数为:" + total); raf.write(b, 0, len); //为了完成断点续传,while循环每次下载的进度,都写入一个文本临时文件中 RandomAccessFile rafProgress = new RandomAccessFile(fileProgess, "rwd"); rafProgress.write((total + "").getBytes()); rafProgress.close(); currentPbProgress += len; //所有线程每次下载len个长度的字节,都会写到进度条的总进度中 pb.setProgress(currentPbProgress); handler.sendEmptyMessage(0); } System.out.println("线程" + threadId + "下载完毕---------------------"); raf.close(); finishedThreadCount++; //三个线程全部下载完毕,才去删除文本临时文件 synchronized (path) { if(finishedThreadCount == 3){ for (int i = 0; i < threadCount; i++) { File f = new File(Environment.getExternalStorageDirectory(), i + ".txt"); if(f.exists()) f.delete(); } finishedThreadCount = 0; } } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。