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

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

时间: 2024-10-10 13:48:47

安卓实训第七天---多线程下载实现(进度条)的相关文章

赵雅智_android多线程下载带进度条

progressBar说明 在某些操作的进度中的可视指示器,为用户呈现操作的进度,还它有一个次要的进度条,用来显示中间进度,如在流媒体播放的缓冲区的进度.一个进度条也可不确定其进度.在不确定模式下,进度条显示循环动画.这种模式常用于应用程序使用任务的长度是未知的. XML重要属性 android:progressBarStyle:默认进度条样式 android:progressBarStyleHorizontal:水平样式 progressBar重要方法 getMax():返回这个进度条的范围的

安卓实训第八天----Activity的生命周期

一.Activity的使用: package com.example.activity; import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; public class FirstActivity exte

安卓实训第九天---Activity的复习以及在Onstart里设置网络连接

今天,首先对Activity的生命周期进行复习: (下面的截图部分是借鉴自赵雅智老师的博客...) Activity的完整生命周期自第一次调用onCreate()开始,直至调用onDestroy()为止.Activity在onCreate()中设置所有"全局"状态以完成初始化,而在onDestroy()中释放所有系统资源.例如,如果Activity有一个线程在后台运行从网络下载数据,它会在onCreate()创建线程,而在 onDestroy()销毁线程. 刚进入activity: 按

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

上午:老师首先回顾了昨天作业. 首先在安卓工程中的TOOLS文件中,解析字节流那里,不用改变,而是把服务器端的编码方式变为UTF-8,然后将在安卓工程的LoginActivity类中的USERNAME给他强制转换下. 总结一句话:如果一个字符通过某个编码转换成字节码之后,那你在转换的时候必须拿到转换之前的字节码 补充:如何改变mysql连接工具的编码方式: jdbc:mysql://localhost:3306/databasename?useUnicode=true&characterEnco

安卓实训第五天

首先讲了如何将文件上传到SD卡中: package com.example.lesson05_02; import java.io.File; import java.io.FileNotFoundException; import org.apache.http.Header; import android.app.Activity; import android.os.Bundle; import android.text.TextUtils; import android.view.Vie

安卓实训第十天:利用SharedPreferences来实现数据的保存和读取,以及实现手机电话备份,XMLserializer

一.利用SharedPreferences来实现数据的保存和读取: 1.Mainactivity: package com.example.sharedpreferencesdemo; import com.example.sharedpreferencesdemo.util.SharedPreferencesUtil; import android.app.Activity; import android.app.AlertDialog; import android.content.Cont

安卓实训第十四天---使用ContentProvider共享数据,并且利用ContentResolver监听共享数据

ContentProvider: 一.当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据:采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据.而使用ContentProvider共享数据的好处是统一了数据访问方式. 第二步需要在AndroidManif

AsyncTask的使用 (二)图片下载,进度条

import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.Ht

recyclerView中多任务下载文件进度条更新的问题

在recyclerview或listview中进行下载时,由于条目复用等原因会导致下载的进度条更新错乱. 你可能觉得条目复用问题我解决过那么多次,加个tag了啥的就解决了不是. 有这个想法说明你没做过下载的处理.因为在下载的过程中,进度条是一直处于更新状态,所以传统的解觉条目复用的方式并不起作用. 解决方式有两种: 1.进度更新时把进度条进度存到bean中.然后在获取进度的循环中同步刷新adapter. 2.进度更新时把进度条进度存到bean中.写一个轮询刷新adapter.