android簡單的多執行緒下載
阿新 • • 發佈:2019-02-11
package www.csdn.net.download; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL; import www.csdn.net.tools.StreamTools; import android.R.string; import android.app.Activity; import android.os.Bundle; import android.os.Environment; import android.text.TextUtils; 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 { private int threadRunning = 3; private int threadNum = 3; private EditText et_url; private TextView tv_pd; private ProgressBar pBar; private int currentProgress; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); et_url = (EditText) findViewById(R.id.ed_url); tv_pd = (TextView) findViewById(R.id.tv_pd); pBar = (ProgressBar) findViewById(R.id.pb); File sdDir = Environment.getExternalStorageDirectory(); File pdfile = new File(sdDir, "pd.txt"); FileInputStream is=null; try { if (pdfile.exists()) { //首先判斷檔案是否存在 is = new FileInputStream(pdfile); } } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (is!=null) { String value = StreamTools.streamTostr(is); String arr[] = value.split(";"); pBar.setMax(Integer.valueOf(arr[0]));//最大值 currentProgress = Integer.valueOf(arr[1]);//當前值 pBar.setProgress(currentProgress);//顯示文字 //String percent = arr[1]; tv_pd.setText(arr[2]); } } public void downLoadFile(View v) { // 獲取下載路徑 final String spec = et_url.getText().toString(); if (TextUtils.isEmpty(spec)) { Toast.makeText(this, "下載地址不為空", Toast.LENGTH_LONG).show(); } else { new Thread() { @Override public void run() { // TODO Auto-generated method stub try { URL url = new URL(spec); HttpURLConnection httpURLConnection = (HttpURLConnection) url .openConnection(); // 設定請求的標頭檔案資訊還有時間 httpURLConnection.setRequestMethod("GET"); httpURLConnection.setConnectTimeout(5000); httpURLConnection.setReadTimeout(5000); if (httpURLConnection.getResponseCode() == 200) { int fileLength = httpURLConnection .getContentLength(); // 設定進度條最大值 pBar.setMax(fileLength); // 判斷是否存在外部儲存裝置 if (Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED)) { File sdFile = Environment .getExternalStorageDirectory(); // 獲取檔名稱 String fileName = spec.substring(spec .lastIndexOf("/") + 1); // 建立儲存檔案 File file = new File(sdFile, fileName); // 穿件隨機可以訪問的檔案物件 RandomAccessFile accessFile = new RandomAccessFile( file, "rwd"); // 設定檔案大小 accessFile.setLength(fileLength); accessFile.close(); // 首先計算出每個執行緒下載的大小 開始位置 結束位置 int threadSize = fileLength / threadNum; for (int threadId = 1; threadId <= 3; threadId++) { int startIndex = (threadId - 1) * threadSize;// 開始位置 int endIndex = threadId * threadSize - 1; if (threadId == threadNum) {// 最後一個執行緒 endIndex = fileLength; } System.out.println("當前執行緒--" + threadId + "開始位置---" + startIndex + "結束位置---" + endIndex + "執行緒大小---"); // 開啟執行緒下載 new DownLoadThread(threadId, startIndex, endIndex, spec, fileName).start(); } } else { MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Toast.makeText(MainActivity.this, "sd卡不可用", 1).show(); } }); } } else { // 線上程中執行 MainActivity.this.runOnUiThread(new Runnable() { public void run() { Toast.makeText(MainActivity.this, "伺服器返回錯誤", 1).show(); ; } }); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }.start(); } } class DownLoadThread extends Thread { private int threadId; private int startIndex; private int endIndex; private String path; private String fileName; public DownLoadThread(int threadId, int startIndex, int endIndex, String path, String fileName) { super(); this.threadId = threadId; this.startIndex = startIndex; this.endIndex = endIndex; this.path = path; this.fileName = fileName; } @Override public void run() { File sdFile = Environment.getExternalStorageDirectory(); // 獲取每個執行緒下載的記錄檔案 File recordFile = new File(sdFile, threadId + ".txt"); // 可以通過每個執行緒去下載檔案了。 try { // 首先從本地檔案上讀取已經下載檔案的開始位置 if (recordFile.exists()) { // 讀取檔案的內容 InputStream is = new FileInputStream(recordFile); // 利用工具類轉換 String value = StreamTools.streamTostr(is); // 獲取記錄位置 int recordIndex = Integer.parseInt(value); startIndex = recordIndex;// 記錄的位置複製給開始的位置即可 } URL url = new URL(path);// 通過path路徑構建URL物件 // 通過URL物件的開啟連線,返回物件 HttpURLConnection httpURLConnection = (HttpURLConnection) url .openConnection(); // 設定請求頭 httpURLConnection.setRequestMethod("GET"); httpURLConnection.setConnectTimeout(5000); // 設定下載檔案的開始位置和結束位置 httpURLConnection.setRequestProperty("Range", "bytes=" + startIndex + "-" + endIndex); // 獲取的狀態嗎 int code = httpURLConnection.getResponseCode(); if (code == 206) { // 獲取每個執行緒返回的流物件: InputStream inputStream = httpURLConnection .getInputStream(); // 定一寫入檔案的路徑 // 根據路徑建立檔案 File file = new File(sdFile, fileName); // 根據檔案建立她RandomAccessFile物件 RandomAccessFile raf = new RandomAccessFile(file, "rwd"); raf.seek(startIndex); // 定義讀取的長度 int len = 0; byte buffer[] = new byte[1024 * 1024 * 10]; int total = 0; // 迴圈讀取 while ((len = inputStream.read(buffer)) != -1) { System.out.println("當前執行緒--" + threadId + "--已經下載了" + (startIndex + total)); @SuppressWarnings("resource") RandomAccessFile threadfile = new RandomAccessFile( new File(sdFile, threadId + ".txt"), "rwd"); threadfile.writeBytes((startIndex + total) + ""); threadfile.close(); raf.write(buffer, 0, len); total += len; //解決同步問題 synchronized (MainActivity.this) { currentProgress += len; pBar.setProgress(currentProgress); final String percent = currentProgress*100L/pBar.getMax()+"%"; MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub tv_pd.setText("當前進度是:" + percent); } }); RandomAccessFile pbfile = new RandomAccessFile(new File(sdFile, "pd.txt"),"rwd"); pbfile.writeBytes(pBar.getMax()+";"+currentProgress+";"+percent); pbfile.close(); } } raf.close(); inputStream.close(); MainActivity.this.runOnUiThread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Toast.makeText(MainActivity.this, "當前執行緒----" + threadId + "下載完畢", 1).show(); } }); deleteRecordFiles(); } else { runOnUiThread(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Toast.makeText(MainActivity.this, "伺服器端下載錯誤", 1) .show(); } }); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public synchronized void deleteRecordFiles() { File sdFile = Environment.getExternalStorageDirectory(); threadRunning--; if (threadRunning == 0) { for (int i = 1; i < 3; i++) { File recordFile = new File(sdFile, i + ".txt"); if (recordFile.exists()) { recordFile.delete();// 刪除掉檔案 } File pdFile = new File(sdFile,"pd.txt"); if (pdFile.exists()) { pdFile.delete(); } } } } }
對於多執行緒下載理解還不是很透徹,在測試的過程中出現了不少bug,比如斷點儲存時會超出100%,進入下載後退出再進入後悔停止執行,再重新進入後才能下載。望大神們指教。