安卓实训第七天---多线程下载实现(进度条)

Posted mfmdaoyou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了安卓实训第七天---多线程下载实现(进度条)相关的知识,希望对你有一定的参考价值。

 
 
 
 
 
 
 
 
 
packagecom.example.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 android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
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 ProgressBar progressBar;

	private TextView tv_pb;

	private int currentProgress = 0;

	private boolean flag = true;
	// 记录进度条的值
	public static int pb_count = 0;
	public static Handler handler;
	public static final int TEXTVALUE = 1;
	public static int pb_num = 0;
	public static int size = 0;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		// 获取控件对象
		et_url = (EditText) findViewById(R.id.et_url);
		progressBar = (ProgressBar) findViewById(R.id.tv_jindu);
		tv_pb = (TextView) findViewById(R.id.tv_pb);
		File sdDir = Environment.getExternalStorageDirectory();
		File pdFile = new File(sdDir, "pb.txt");
		InputStream is = null;
		try {
			if (pdFile.exists()) {
				is = new FileInputStream(pdFile);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
		if (is != null) {
			String value = StreamTools.streamTostr(is);
			String arr[] = value.split(";");
			progressBar.setMax(Integer.valueOf(arr[0]));// 最大值
			currentProgress = Integer.valueOf(arr[1]);// 当前值
			progressBar.setProgress(currentProgress);
			;
			tv_pb.setText("当前的进度是" + arr[2] + "%");
		}
	}

	public void downLoadFile(View v) {
		// 訪问地址:
		final String spec = et_url.getText().toString();// "http://172.16.237.144:8080/Login/football.jpg";
		if (TextUtils.isEmpty(spec)) {
			Toast.makeText(this, "下载地址不能为空", Toast.LENGTH_LONG).show();
		} else {
			new Thread() {
				public void run() {
					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();
							// 设置进度条的最大值
							progressBar.setMax(fileLength);
							// 推断你的设备SDCard是否可用
							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循环开启线程处理
								for (int threadId = 1; threadId <= 3; threadId++) {
									int startIndex = (threadId - 1)
											* threadSize;// 開始位置
									int endIndex = threadId * threadSize - 1;
									if (threadId == threadNum) {// 最后一个线程
										endIndex = fileLength - 1;
									}
									System.out.println("当前线程--" + threadId
											+ "開始位置---" + startIndex
											+ "结束位置---" + endIndex + "线程大小---");
									// 开启线程下载要用Start方法
									new DownLoadThread(threadId, startIndex,
											endIndex, spec, fileName).start();
								}
							} else {
								MainActivity.this.runOnUiThread(new Runnable() {

									@Override
									public void run() {
										Toast.makeText(MainActivity.this,
												"设备的SD卡不可用", Toast.LENGTH_LONG)
												.show();
									}
								});
							}
						} else {
							// 这里用这个能够让它在主线程中执行
							MainActivity.this.runOnUiThread(new Runnable() {

								@Override
								public void run() {
									Toast.makeText(MainActivity.this,
											"server端返回错误", Toast.LENGTH_LONG)
											.show();
								}
							});
						}
					} catch (Exception e) {
						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() {
			// 能够通过每一个线程去下载文件了。
			try {
				File sdfile = Environment.getExternalStorageDirectory();
				// 获取每一个线程下载的记录文件
				File recordFile = new File(sdfile, threadId + ".txt");
				// 推断记录文件是否存在
				if (recordFile.exists()) {
					// 读取文件的内容
					InputStream is = new FileInputStream(recordFile);
					// 利用工具类转换
					String value = StreamTools.streamTostr(is);
					// 获取记录位置
					int recordIndex = Integer.parseInt(value);
					// 记录的位置复制给開始的位置就可以
					startIndex = recordIndex;
				}
				// 通过path路径构建URL对象
				URL url = new URL(path);
				// 通过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();

					// 获取文件名 由于已经通过那边传过来了
					// String fileName =
					// path.substring(path.lastIndexOf("/")+1);
					// 外部存储设备的路径

					File file = new File(sdfile, fileName);
					// 依据文件创建她RandomAccessFile对象
					RandomAccessFile raf = new RandomAccessFile(file, "rwd");
					raf.seek(startIndex);
					// 定义读取的长度
					int len = 0;
					byte buffer[] = new byte[50];
					int total = 0;
					// 循环读取
					while ((len = inputStream.read(buffer)) != -1) {
						System.out.println("当前线程--" + threadId + "--已经下载了"
								+ (startIndex + total));
						// 创建线程下载记录的文件
						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;
							progressBar.setProgress(currentProgress);
							// 计算百分比的操作 int
							final String percent = currentProgress * 100L
									/ progressBar.getMax() + "";
							MainActivity.this.runOnUiThread(new Runnable() {
								@Override
								public void run() {
									tv_pb.setText("当前的进度是:" + percent + "%");
								}
							});
							RandomAccessFile pbfile = new RandomAccessFile(
									new File(sdfile, "pb.txt"), "rwd");
							pbfile.writeBytes(progressBar.getMax() + ";"
									+ currentProgress + ";" + percent);
							pbfile.close();
						}

					}
					raf.close();
					inputStream.close();
					MainActivity.this.runOnUiThread(new Runnable() {
						@Override
						public void run() {
							// System.out.println("当前线程----"+threadId+"完成下载");
							Toast.makeText(MainActivity.this,
									"当前线程----" + threadId + "完成下载",
									Toast.LENGTH_LONG).show();
						}
					});
					deleteRecordFiles();
				} else {
					MainActivity.this.runOnUiThread(new Runnable() {
						@Override
						public void run() {
							Toast.makeText(MainActivity.this, "server端下载错误",
									Toast.LENGTH_LONG).show();
						}
					});
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	public synchronized void deleteRecordFiles() {
		File sdfile = Environment.getExternalStorageDirectory();
		System.out.println("-------------------------");
		threadRunning--;
		if (threadRunning == 0) {
			for (int i = 1; i <= 3; i++) {
				File recordFile = new File(sdfile, i + ".txt");
				if (recordFile.exists()) {
					boolean flag1 = recordFile.delete();// 删除掉文件
					System.out.println("下载记录" + i + "文件已" + flag1 + "删除");
				}
				File pdFile = new File(sdfile, "pb.txt");
				if (pdFile.exists()) {
					boolean flag2 = pdFile.delete();
					System.out.println("进度条记录文件已" + flag2 + "删除");
				}
			}
		}
	}

	public void displayMsg() {

	}
}


BUG注意事项:

1、继续线程下载的文件一定要运行threadfile.close(),不然就无法运行后面的删除TXT文件部分。

2、一定要注意下载速度的设置,不能太快。超过传输文件的大小。不然会导致模拟器死掉。;


以上是关于安卓实训第七天---多线程下载实现(进度条)的主要内容,如果未能解决你的问题,请参考以下文章

实训第八天 有关python orm 的学习记录 常用方法01

实训第八天 有关python orm 的学习记录 常用方法02

Python实现下载界面(带进度条,断点续传,多线程多任务下载等)

实训第三天

C# Winform 多线程异步委托进度条

安卓实训第四天--基于HttpClient来完毕数据在server和设备间的交互。