多线程下载
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 | package com.example.mutildownloader2; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.ProtocolException; import java.net.URL; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.app.Activity; import android.text.TextUtils; import android.view.Menu; import android.view.View; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity { protected static final int DOWN_LOAD_ERROR = 1; protected static final int SERVER_ERROR = 2; public static final int DOWN_LAOD_FINSIH = 3; public static final int UPDATE_TEXT = 4; private EditText et_path; private ProgressBar pb; //下载的进度条. public static int threadCount = 3; public static int runningThread = 3 ; public int currentProcess = 0; //当前进度. private TextView tv_process; private Handler handler = new Handler(){ public void handleMessage(android.os.Message msg) { switch (msg.what) { case DOWN_LOAD_ERROR: Toast.makeText(getApplicationContext(), "下载失败", 0).show(); break; case SERVER_ERROR: Toast.makeText(getApplicationContext(), "服务器 错误,下载失败", 0).show(); break; case DOWN_LAOD_FINSIH: Toast.makeText(getApplicationContext(), "文件下载完毕", 0).show(); break; case UPDATE_TEXT: tv_process.setText("当前进度:"+pb.getProgress()*100/pb.getMax()); break; } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_path = (EditText) this.findViewById(R.id.et_path); pb = (ProgressBar) findViewById(R.id.pb); tv_process = (TextView) findViewById(R.id.tv_process); } public void downLoad(View view) { final String path = et_path.getText().toString().trim(); if (TextUtils.isEmpty(path)) { Toast.makeText(this, "下载路径错误", 0).show(); return; } currentProcess = 0; new Thread() { public void run() { try { //String path = "http://192.168.1.100:8080/360.exe"; URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setConnectTimeout(5000); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); if (code == 200) { // 服务器返回的数据的长度 实际上就是文件的长度 int length = conn.getContentLength(); pb.setMax(length);//设置进度条的最大值. System.out.println("文件总长度:" + length); // 在客户端本地 创建出来一个大小跟服务器端文件一样大小的临时文件 RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe", "rwd"); // 指定创建的这个文件的长度 raf.setLength(length); raf.close(); // 假设是3个线程去下载资源. // 平均每一个线程下载的文件的大小. int blockSize = length / threadCount; for (int threadId = 1; threadId <= threadCount; threadId++) { // 第一个线程下载的开始位置 int startIndex = (threadId - 1) * blockSize; int endIndex = threadId * blockSize - 1; if (threadId == threadCount) {// 最后一个线程 下载的长度 要稍微长一点 endIndex = length; } System.out.println("线程:" + threadId + "下载:---" + startIndex + "--->" + endIndex); new DownloadThread(path, threadId, startIndex, endIndex) .start(); } } else { System.out.println("服务器错误."); Message msg = new Message(); msg.what = SERVER_ERROR; handler.sendMessage(msg); } } catch (Exception e) { e.printStackTrace(); Message msg = new Message(); msg.what = DOWN_LOAD_ERROR; handler.sendMessage(msg); } }; }.start(); } /** * 下载文件的子线程 每一个线程 下载对应位置的文件 * * @author Administrator * */ public class DownloadThread extends Thread { private int threadId; private int startIndex; private int endIndex; private String path; /** * @param path * 下载文件在服务器上的路径 * @param threadId * 线程id * @param startIndex * 线程下载的开始位置 * @param endIndex * 线程下载的结束位置. */ public DownloadThread(String path, int threadId, int startIndex, int endIndex) { this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; this.path = path; } @Override public void run() { try { // 检查是否存在 记录下载长度的文件 ,如果存在读取这个文件的数据. //------------------替换成存数据库------------------------- File tempFile = new File("/sdcard/"+threadId + ".txt"); if (tempFile.exists() && tempFile.length() > 0) { FileInputStream fis = new FileInputStream(tempFile); byte[] temp = new byte[1024]; int leng = fis.read(temp); String downloadLen = new String(temp, 0, leng); int downloadlenInt = Integer.parseInt(downloadLen); int alreadyDownlodint = downloadlenInt - startIndex ; currentProcess+=alreadyDownlodint; //计算上次断点 已经下载的文件的长度. startIndex = downloadlenInt;//修改下载的真实的开始位置. fis.close(); } //-------------------------------------------- URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url .openConnection(); conn.setRequestMethod("GET"); // 重要: 请求服务器下载部分的文件 指定文件的位置. conn.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); System.out.println("线程真实下载:" + threadId + "下载:---" + startIndex + "--->" + endIndex); conn.setConnectTimeout(5000); int code = conn.getResponseCode(); // 从服务器请求全部资源 200 ok // 如果从服务器请求部分资源 206 ok if (code == 206) { InputStream is = conn.getInputStream();// 已经设置了 请求的位置 RandomAccessFile raf = new RandomAccessFile("/sdcard/setup.exe", "rwd"); // 随机写文件的时候 从哪个位置开始写 raf.seek(startIndex);// 定位文件 int len = 0; byte[] buffer = new byte[1024]; int total = 0;// 已经下载的数据长度 while ((len = is.read(buffer)) != -1) { RandomAccessFile file = new RandomAccessFile("/sdcard/"+threadId + ".txt", "rwd");// 作用: 记录当前线程下载的数据长度 raf.write(buffer, 0, len); total += len; //System.out.println("线程:" + threadId + "total:" + total); file.write(( total+startIndex+"").getBytes());//记录的是 下载位置. file.close(); //更新进度条 synchronized (MainActivity.this) { currentProcess+=len;//获取所有线程下载的总进度. pb.setProgress(currentProcess);//更改界面上progressbar 进度条的进度 //特殊情况 progressbar progressdialog 进度条对话框 可以直接在子线程里面更新ui 内部代码 特殊处理 Message msg = Message.obtain();//复用旧的消息 避免创建新的消息 msg.what = UPDATE_TEXT; handler.sendMessage(msg); } } is.close(); raf.close(); System.out.println("线程:" + threadId + "下载完毕了..."); } else { System.out.println("线程:" + threadId + "下载失败..."); } // File deleteFile = new File("/sdcard/"+threadId+".txt"); // deleteFile.delete();//当线程下载完毕后 清楚掉 下载的记录 //如何去判断应用程序已经下载完毕. } catch (Exception e) { e.printStackTrace(); }finally{ threadFinish(); } } private synchronized void threadFinish() { runningThread --; if(runningThread==0){//所有的线程 已经执行完毕了. for(int i= 1;i<=3;i++){ File file = new File("/sdcard/"+i+".txt"); file.delete(); } System.out.println("文件下载完毕 ,删除所有的下载记录."); Message msg = new Message(); msg.what = DOWN_LAOD_FINSIH; handler.sendMessage(msg); } } } } |
浙公网安备 33010602011771号