Android开发之多线程下载、断点续传、进度条和文本显示

代码实现了在Android环境下的多线程下载、断点续传、进度条显示和文本显示百分数:

  1 import java.io.BufferedReader;
  2 import java.io.File;
  3 import java.io.FileInputStream;
  4 import java.io.InputStream;
  5 import java.io.InputStreamReader;
  6 import java.io.RandomAccessFile;
  7 import java.net.HttpURLConnection;
  8 import java.net.URL;
  9 
 10 
 11 import android.os.Bundle;
 12 import android.os.Environment;
 13 import android.os.Handler;
 14 import android.app.Activity;
 15 import android.view.Menu;
 16 import android.view.View;
 17 import android.widget.ProgressBar;
 18 import android.widget.TextView;
 19 
 20 public class MainActivity extends Activity {
 21 
 22     static int ThreadCount = 3;
 23     static int finishedThread = 0;
 24     
 25     int currentProgress;
 26     String fileName = "QQPlayer.exe";
 27     //确定下载地址
 28     String path = "http://192.168.13.13:8080/" + fileName;
 29     private ProgressBar pb;
 30     TextView tv;
 31     
 32     Handler handler = new Handler(){
 33         public void handleMessage(android.os.Message msg) {
 34             //把变量改成long,在long下运算
 35             tv.setText((long)pb.getProgress() * 100 / pb.getMax() + "%");
 36         }
 37     };
 38     @Override
 39     protected void onCreate(Bundle savedInstanceState) {
 40         super.onCreate(savedInstanceState);
 41         setContentView(R.layout.activity_main);
 42         pb = (ProgressBar) findViewById(R.id.pb);
 43         tv = (TextView) findViewById(R.id.tv);
 44     }
 45 
 46     public void click(View v){
 47         
 48         Thread t = new Thread(){
 49             @Override
 50             public void run() {
 51                 //发送get请求,请求这个地址的资源
 52                 try {
 53                     URL url = new URL(path);
 54                     HttpURLConnection conn = (HttpURLConnection) url.openConnection();
 55                     conn.setRequestMethod("GET");
 56                     conn.setConnectTimeout(5000);
 57                     conn.setReadTimeout(5000);
 58                     
 59                     if(conn.getResponseCode() == 200){
 60                         //拿到所请求资源文件的长度
 61                         int length = conn.getContentLength();
 62                         
 63                         //设置进度条的最大值就是原文件的总长度
 64                         pb.setMax(length);
 65                         
 66                         File file = new File(Environment.getExternalStorageDirectory(), fileName);
 67                         //生成临时文件
 68                         RandomAccessFile raf = new RandomAccessFile(file, "rwd");
 69                         //设置临时文件的大小
 70                         raf.setLength(length);
 71                         raf.close();
 72                         //计算出每个线程应该下载多少字节
 73                         int size = length / ThreadCount;
 74                         
 75                         for (int i = 0; i < ThreadCount; i++) {
 76                             //计算线程下载的开始位置和结束位置
 77                             int startIndex = i * size;
 78                             int endIndex = (i + 1) * size - 1;
 79                             //如果是最后一个线程,那么结束位置写死
 80                             if(i == ThreadCount - 1){
 81                                 endIndex = length - 1;
 82                             }
 83 //                            System.out.println("线程" + i + "的下载区间是:" + startIndex + "---" + endIndex);
 84                             new DownLoadThread(startIndex, endIndex, i).start();
 85                         }
 86                     }
 87                 } catch (Exception e) {
 88                     // TODO Auto-generated catch block
 89                     e.printStackTrace();
 90                 }
 91             }
 92         };
 93         t.start();
 94     }
 95     
 96     class DownLoadThread extends Thread{
 97         int startIndex;
 98         int endIndex;
 99         int threadId;
100         
101         public DownLoadThread(int startIndex, int endIndex, int threadId) {
102             super();
103             this.startIndex = startIndex;
104             this.endIndex = endIndex;
105             this.threadId = threadId;
106         }
107 
108         @Override
109         public void run() {
110             //再次发送http请求,下载原文件
111             try {
112                 File progressFile = new File(Environment.getExternalStorageDirectory(), threadId + ".txt");
113                 //判断进度临时文件是否存在
114                 if(progressFile.exists()){
115                     FileInputStream fis = new FileInputStream(progressFile);
116                     BufferedReader br = new BufferedReader(new InputStreamReader(fis));
117                     //从进度临时文件中读取出上一次下载的总进度,然后与原本的开始位置相加,得到新的开始位置
118                     int lastProgress = Integer.parseInt(br.readLine());
119                     startIndex += lastProgress;
120                     
121                     //把上次下载的进度显示至进度条
122                     currentProgress += lastProgress;
123                     pb.setProgress(currentProgress);
124                     
125                     //发送消息,让主线程刷新文本进度
126                     handler.sendEmptyMessage(1);
127                     fis.close();
128                 }
129                 System.out.println("线程" + threadId + "的下载区间是:" + startIndex + "---" + endIndex);
130                 HttpURLConnection conn;
131                 URL url = new URL(path);
132                 conn = (HttpURLConnection) url.openConnection();
133                 conn.setRequestMethod("GET");
134                 conn.setConnectTimeout(5000);
135                 conn.setReadTimeout(5000);
136                 //设置本次http请求所请求的数据的区间
137                 conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex);
138                 
139                 //请求部分数据,相应码是206
140                 if(conn.getResponseCode() == 206){
141                     //流里此时只有1/3原文件的数据
142                     InputStream is = conn.getInputStream();
143                     byte[] b = new byte[1024];
144                     int len = 0;
145                     int total = 0;
146                     //拿到临时文件的输出流
147                     File file = new File(Environment.getExternalStorageDirectory(), fileName);
148                     RandomAccessFile raf = new RandomAccessFile(file, "rwd");
149                     //把文件的写入位置移动至startIndex
150                     raf.seek(startIndex);
151                     while((len = is.read(b)) != -1){
152                         //每次读取流里数据之后,同步把数据写入临时文件
153                         raf.write(b, 0, len);
154                         total += len;
155                         System.out.println("线程" + threadId + "下载了" + total);
156                         
157                         //每次读取流里数据之后,把本次读取的数据的长度显示至进度条
158                         currentProgress += len;
159                         pb.setProgress(currentProgress);
160                         //发送消息,让主线程刷新文本进度
161                         handler.sendEmptyMessage(1);
162                         
163                         //生成一个专门用来记录下载进度的临时文件
164                         RandomAccessFile progressRaf = new RandomAccessFile(progressFile, "rwd");
165                         //每次读取流里数据之后,同步把当前线程下载的总进度写入进度临时文件中
166                         progressRaf.write((total + "").getBytes());
167                         progressRaf.close();
168                     }
169                     System.out.println("线程" + threadId + "下载完毕-------------------小志参上!");
170                     raf.close();
171                     
172                     finishedThread++;
173                     synchronized (path) {
174                         if(finishedThread == ThreadCount){
175                             for (int i = 0; i < ThreadCount; i++) {
176                                 File f = new File(Environment.getExternalStorageDirectory(), i + ".txt");
177                                 f.delete();
178                             }
179                             finishedThread = 0;
180                         }
181                     }
182                     
183                 }
184             } catch (Exception e) {
185                 // TODO Auto-generated catch block
186                 e.printStackTrace();
187             }
188         }
189     }
190 
191 }
原文地址:https://www.cnblogs.com/liyiran/p/5062128.html