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 }
直面挑战,躬身入局