Android核心技術-day05-05-安卓下的多執行緒下載(帶ProgressBar)有bug版
阿新 • • 發佈:2018-11-07
package com.gaozewen.multidownloader; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.view.View; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ProgressBar; import android.widget.Toast; import com.lidroid.xutils.HttpUtils; import com.lidroid.xutils.exception.HttpException; import com.lidroid.xutils.http.ResponseInfo; import com.lidroid.xutils.http.callback.RequestCallBack; 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 java.util.ArrayList; public class MainActivity extends AppCompatActivity { private EditText mEt_thread_count; private EditText mEt_path; private LinearLayout mLl_container; public String path = "http://192.168.1.102:8080/xunlei.exe"; public int totalThreadCount = 0; public int runningThreadCount = 0; private ArrayList<ProgressBar> mPbs; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 1. 找到控制元件 // 2. 在 button 點選事件中下載檔案 // 3. 下載的時候顯示下載進度 mEt_thread_count = (EditText) findViewById(R.id.et_thread_count); mEt_path = (EditText) findViewById(R.id.et_path); mLl_container = (LinearLayout) findViewById(R.id.ll_container); } /** * 用第三方控制元件 xUtils 下載 * @param view */ public void download2(View view) { path = mEt_path.getText().toString().trim(); HttpUtils http = new HttpUtils(); http.download(path, getCacheDir() + "/" + getDownloadFileName(path), true, new RequestCallBack<File>() { @Override public void onSuccess(ResponseInfo<File> responseInfo) { Toast.makeText(MainActivity.this,"下載成功", Toast.LENGTH_SHORT).show(); } @Override public void onFailure(HttpException e, String s) { Toast.makeText(MainActivity.this,"下載失敗", Toast.LENGTH_SHORT).show(); } @Override public void onLoading(long total, long current, boolean isUploading) { System.out.println(current); super.onLoading(total, current, isUploading); } }); } public void download(View view) { totalThreadCount = Integer.valueOf(mEt_thread_count.getText().toString().trim()); path = mEt_path.getText().toString().trim(); mLl_container.removeAllViews(); mPbs = new ArrayList<>(); for (int i = 0; i < totalThreadCount; i++) { // 有幾個執行緒就建立幾個 進度條 ProgressBar pb = (ProgressBar) View.inflate(this, R.layout.pb, null); mLl_container.addView(pb); mPbs.add(pb); } new Thread() { @Override public void run() { try { URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); int code = conn.getResponseCode(); if (code == 200) { int length = conn.getContentLength(); System.out.println("file length: " + length); // 建立一個空的檔案,並且設定他的檔案長度等於伺服器上的檔案長度 RandomAccessFile raf = new RandomAccessFile(getCacheDir() + "/" + getDownloadFileName(path), "rw"); raf.setLength(length); raf.close(); int blockSize = length / totalThreadCount; System.out.println("every block size: " + blockSize); runningThreadCount = totalThreadCount; for (int threadId = 0; threadId < totalThreadCount; threadId++) { int startPosition = blockSize * threadId; int endPosition = blockSize * (threadId + 1) - 1; // -1 是到當前塊的最後一個位元組 if (threadId == (totalThreadCount - 1)) { endPosition = length - 1; } System.out.println(String.format("threadId: %s\ndownload rage: %s to %s", threadId, startPosition, endPosition)); new DownloadThread(threadId, startPosition, endPosition).start(); } } else { } } catch (Exception e) { e.printStackTrace(); } } }.start(); } /** * 從網路路徑獲取檔名 * * @param path 網路路徑 * @return 檔名 */ private static String getDownloadFileName(String path) { return path.substring(path.lastIndexOf("/") + 1); } /** * 下載檔案的執行緒 */ private class DownloadThread extends Thread { /** * 執行緒 id */ private int threadId; /** * 當前執行緒下載的起始位置 */ private int startPosition; /** * 當前執行緒下載的終止位置 */ private int endPosition; /** * 當前執行緒需要去下載的總共的位元組 */ private int threadTotal; /** * 上次斷點 下載的總共位元組數 */ private int lastDownloadTotalSize; public DownloadThread(int threadId, int startPosition, int endPosition) { this.threadId = threadId; this.startPosition = startPosition; this.endPosition = endPosition; this.threadTotal = endPosition - startPosition; mPbs.get(threadId).setMax(threadTotal); // 設定進度條 } @Override public void run() { System.out.println(String.format("threadID: %s begin working", threadId)); // lest thread download it's self range data try { // 查詢 記錄斷點資訊的檔案 File finfo = new File(getCacheDir(), totalThreadCount + getDownloadFileName(path) + threadId + ".txt"); if (finfo.exists() && finfo.length() > 0) { // 斷點下載 FileInputStream fis = new FileInputStream(finfo); BufferedReader br = new BufferedReader(new InputStreamReader(fis)); String lastPosition = br.readLine(); int intLastPosition = Integer.parseInt(lastPosition); // 進度條斷點續借位置 lastDownloadTotalSize = intLastPosition - startPosition; // This thread download data before times; startPosition = intLastPosition; fis.close(); } // 第一次下載 URL url = new URL(path); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setRequestMethod("GET"); System.out.println(String.format("begin and end: %s range of download: %s to %s", threadId, startPosition, endPosition)); conn.setRequestProperty("Range", String.format("bytes=%s-%s", startPosition, endPosition)); // 從伺服器下載資源 int code = conn.getResponseCode(); if (code == 206) { InputStream is = conn.getInputStream(); // 第一次沒有這個檔案則建立,下次直接開啟這個檔案 RandomAccessFile raf = new RandomAccessFile(getCacheDir() + "/" + getDownloadFileName(path), "rw"); // !!! position of begin to write raf.seek(startPosition); // 將指標移動到這次開始續傳的位置 byte[] buffer = new byte[1024]; int len = -1; int total = 0; // 當前執行緒 這次下載的資料 while ((len = is.read(buffer)) != -1) { raf.write(buffer, 0, len); total += len; // 建立記錄 儲存當前執行緒下載的位置 (注意: rwd 同步實時寫入到裝置中) RandomAccessFile infoRaf = new RandomAccessFile(getCacheDir() + "/" + totalThreadCount + getDownloadFileName(path) + threadId + ".txt", "rwd"); infoRaf.write(String.valueOf(startPosition + total).getBytes()); infoRaf.close(); // 每次讀寫顯示一個進度 mPbs.get(threadId).setProgress(total + lastDownloadTotalSize); } raf.close(); is.close(); System.out.println(String.format("thread: %s download complete...", threadId)); } else { System.out.println("request download failed"); } } catch (Exception e) { e.printStackTrace(); } finally { synchronized (MainActivity.class) { runningThreadCount--; if (runningThreadCount <= 0) { // 多執行緒下載完成 刪除 位置資訊檔案 System.out.println("multi thread download complete."); for (int i = 0; i < totalThreadCount; i++) { File positionFile = new File(getCacheDir(),totalThreadCount + getDownloadFileName(path) + i + ".txt"); // System.out.println(positionFile.delete()); } } } } } } }