1. 程式人生 > >android簡單的多執行緒下載

android簡單的多執行緒下載

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%,進入下載後退出再進入後悔停止執行,再重新進入後才能下載。望大神們指教。