Android_05_多线程断点续传下载

来源:转载


MainActivity.java

 

package com.itheima.mobilemultidownload;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 android.os.Bundle;import android.os.Environment;import android.os.Handler;import android.app.Activity;import android.view.Menu;import android.view.View;import android.widget.ProgressBar;import android.widget.TextView;public class MainActivity extends Activity { static int ThreadCount = 3; static int finishedThread = 0; int currentProgress; String fileName = QQPlayer.exe; //确定下载地址 String path = http://192.168.13.13:8080/ + fileName; private ProgressBar pb; TextView tv; Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { //把变量改成long,在long下运算,不然当文件很大时,文本进度就会出现负数的情况 tv.setText((long)pb.getProgress() * 100 / pb.getMax() + %); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); 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() { //发送get请求,请求这个地址的资源 try { //这次请求是为了获取文件的大小,以方便设置虚拟的临时文件的大小 URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod(GET); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); if(conn.getResponseCode() == 200){ //拿到所请求资源文件的长度 int length = conn.getContentLength(); //设置进度条的最大值就是原文件的总长度 pb.setMax(length); File file = new File(Environment.getExternalStorageDirectory(), fileName); //生成临时文件,其中rwd表示直接写入磁盘,而不是在中途将其缓存一部分,这防止一断电,有些数据还未写入磁盘; RandomAccessFile raf = new RandomAccessFile(file, rwd); //事先设置好临时文件的大小 raf.setLength(length); //最后记得将其关闭 raf.close(); //计算出每个线程应该下载多少字节 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()是在for()循环里边的,所以有三个线程,这就对了! new DownLoadThread(startIndex, endIndex, i).start(); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }; t.start(); } 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() { //再次发送http请求,下载原文件 try { //生成一个.txt文件是为了保存上次下载完文件后的结束索引,然后把 File progressFile = new File(Environment.getExternalStorageDirectory(), threadId + .txt); //判断进度临时文件是否存在 if(progressFile.exists()){ FileInputStream fis = new FileInputStream(progressFile); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); //从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置 int lastProgress = Integer.parseInt(br.readLine()); startIndex += lastProgress; //把上次下载的进度显示至进度条 currentProgress += lastProgress; //关于进度条的刷新,可以在子线程中显示,具体自己以后去分析其原因, //应该是在其内部做了相应的处理 pb.setProgress(currentProgress); //发送消息,让主线程刷新文本进度 handler.sendEmptyMessage(1); fis.close(); } System.out.println(线程 + threadId + 的下载区间是: + startIndex + --- + endIndex); HttpURLConnection conn; URL url = new URL(path); conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod(GET); conn.setConnectTimeout(5000); conn.setReadTimeout(5000); //设置本次http请求所请求的数据的区间 conn.setRequestProperty(Range, bytes= + startIndex + - + endIndex); //请求部分数据,相应码是206 if(conn.getResponseCode() == 206){ //流里此时只有1/3原文件的数据 InputStream is = conn.getInputStream(); byte[] b = new byte[1024]; int len = 0; int total = 0; //拿到临时文件的输出流 File file = new File(Environment.getExternalStorageDirectory(), fileName); RandomAccessFile raf = new RandomAccessFile(file, rwd); //把文件的写入位置移动至startIndex, //这就是我们为什么使用RandomAccessFile而不用FileOutputStream的原因, //因为其seek方法可以很容易在文件中定位 raf.seek(startIndex); while((len = is.read(b)) != -1){ //每次读取流里数据之后,同步把数据写入临时文件 raf.write(b, 0, len); total += len; System.out.println(线程 + threadId + 下载了 + total); //每次读取流里数据之后,把本次读取的数据的长度显示至进度条 currentProgress += len; pb.setProgress(currentProgress); //发送消息,让主线程刷新文本进度 handler.sendEmptyMessage(1); //生成一个专门用来记录下载进度的临时文件 RandomAccessFile progressRaf = new RandomAccessFile(progressFile, rwd); //每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中 progressRaf.write((total + ).getBytes()); progressRaf.close(); } System.out.println(线程 + threadId + 下载完毕-------------------小志参上!); raf.close(); finishedThread++; synchronized (path) { if(finishedThread == ThreadCount){ for (int i = 0; i < ThreadCount; i++) { File f = new File(Environment.getExternalStorageDirectory(), i + .txt); f.delete(); } finishedThread = 0; } } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }}

activity_main.xml

 

 


注:也可以使用Github上别人写好的方法,直接调用即可;

 

 



分享给朋友:
您可能感兴趣的文章:
随机阅读: