android 多线程下载文件案例

1.下载类
package com.young.download.factory;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;

import android.util.Log;

/**
 * 
 * 文件下载类
 * 
 */
public class FileDownloadThread extends Thread {
	private static final String TAG = "FileDownloadThread";
	/** 缓冲区 */
	private static final int BUFF_SIZE = 1024;
	/** 需要下载的URL */
	private URL url;
	/** 缓存的FIle */
	private File file;
	/** 开始位置 */
	private int startPosition;
	/** 结束位置 */
	private int endPosition;
	/** 当前位置 */
	private int curPosition;
	/** 完成 */
	private boolean finished = false;
	/** 已经下载多少 */
	private int downloadSize = 0;

	/***
	 * 分块文件下载,可以创建多线程模式
	 * 
	 * @param url
	 *            下载的URL
	 * @param file
	 *            下载的文件
	 * @param startPosition
	 *            开始位置
	 * @param endPosition
	 *            结束位置
	 */
	public FileDownloadThread(URL url, File file, int startPosition,
			int endPosition) {
		this.url = url;
		this.file = file;
		this.startPosition = startPosition;
		this.curPosition = startPosition;
		this.endPosition = endPosition;
		Log.e(TAG, toString());
	}

	@Override
	public void run() {
		BufferedInputStream bis = null;
		RandomAccessFile rAccessFile = null;
		byte[] buf = new byte[BUFF_SIZE];
		URLConnection conn = null;
		try {
			conn = url.openConnection();
			conn.setConnectTimeout(10000);// 设置超时
			conn.setReadTimeout(10000);
			conn.setAllowUserInteraction(true);
			System.out.println(this.getName() + " startPosition "
					+ startPosition + " endPosition " + endPosition);
			// 根据范围下载数据
			conn.setRequestProperty("Range", "bytes=" + (startPosition) + "-"
					+ endPosition);
			// 读写
			rAccessFile = new RandomAccessFile(file, "rwd");
			// 从某个地方开始写入数据
			rAccessFile.seek(startPosition);
			bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE);
			// 当前位置小于结束位置 继续下载
			while (curPosition < endPosition) 
			{
				int len = bis.read(buf, 0, BUFF_SIZE);
				// 下载完成
				if (len == -1) {
					break;
				}
				rAccessFile.write(buf, 0, len);
				curPosition = curPosition + len;
				// 如果下载多了,则减去多余部分
				if (curPosition > endPosition) { 
					System.out.println("  curPosition > endPosition  !!!!");
					int extraLen = curPosition - endPosition;
					downloadSize += (len - extraLen + 1);
				} else {
					downloadSize += len;
				}
			}
			this.finished = true; // 当前阶段下载完成
			Log.e(TAG, "当前" + this.getName() + "下载完成");
		} catch (Exception e) {
			Log.e(TAG, "download error Exception " + e.getMessage());
			e.printStackTrace();
		} finally {
			try {
				// 关闭流
				bis.close();
				rAccessFile.close();
			} catch (IOException e) {
				Log.e("AccessFile", "AccessFile IOException " + e.getMessage());
			}
		}
		super.run();
	}

	/**
	 * 是否完成当前段下载完成
	 * 
	 * @return
	 */
	public boolean isFinished() {
		return finished;
	}

	/**
	 * 已经下载多少
	 * 
	 * @return
	 */
	public int getDownloadSize() {
		return downloadSize;
	}

	@Override
	public String toString() {
		return "FileDownloadThread [url=" + url + ", file=" + file
				+ ", startPosition=" + startPosition + ", endPosition="
				+ endPosition + ", curPosition=" + curPosition + ", finished="
				+ finished + ", downloadSize=" + downloadSize + "]";
	}
}



2.更新信息处理类
package com.young.download.factory;

import java.io.File;
import java.io.RandomAccessFile;
import java.net.URL;
import java.net.URLConnection;

import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.young.download.util.FileUtil;

/**
 * 多线程下载,UI更新类
 * 
 **/
public class MultiThreadDownload extends Thread {
	private static final String TAG = "MultiThreadDownload";
	/** 每一个线程需要下载的大小 */
	private int blockSize;
	/***
	 * 线程数量<br>
	 * 默认为5个线程下载
	 */
	private int threadNum = 2;
	/*** 文件大小 */
	private int fileSize;
	/** * 已经下载多少 */
	private int downloadSize;
	/** 文件的url,线程编号,文件名称 */
	private String UrlStr, ThreadNo, fileName;
	/*** 保存的路径 */
	private String savePath;
	/** 下载的百分比 */
	private int downloadPercent = 0;
	/** 下载的 平均速度 */
	private int downloadSpeed = 0;
	/** 下载用的时间 */
	private int usedTime = 0;
	/** 当前时间 */
	private long curTime;
	/** 是否已经下载完成 */
	private boolean completed = false;
	private Handler handler;

	/**
	 * 下载的构造函数
	 * 
	 * @param url
	 *            请求下载的URL
	 * @param handler
	 *            UI更新使用
	 * @param savePath
	 *            保存文件的路径
	 */
	public MultiThreadDownload(Handler handler, String url, String savePath) {
		this.handler = handler;
		this.UrlStr = url;
		this.savePath = savePath;
		Log.e(TAG, toString());
	}

	@Override
	public void run() {

		FileDownloadThread[] fds = new FileDownloadThread[threadNum];// 设置线程数量
		try {
			URL url = new URL(UrlStr);
			URLConnection conn = url.openConnection();
			fileSize = conn.getContentLength();

			this.fileName = FileUtil.getFileName(UrlStr);
			// 只创建一个文件,saveFile下载内容
			File saveFile = new File(savePath + "/" + fileName);
			Log.e(TAG, "文件一共:" + fileSize + " savePath " + savePath
					+ "  fileName  " + fileName);
			// 下载的文件内容
			RandomAccessFile accessFile = new RandomAccessFile(saveFile, "rwd");
			// 设置本地文件的长度和下载文件相同
			accessFile.setLength(fileSize);
			accessFile.close();
			// Handler更新UI,发送消息
			sendMsg(FileUtil.startDownloadMeg);
			// 每个线程下载的数据量
			blockSize = ((fileSize % threadNum) == 0) ? (fileSize / threadNum)
					: (fileSize / threadNum + 1);
			Log.e(TAG, "每个线程分别下载 :" + blockSize);

			for (int i = 0; i < threadNum; i++) {
				int curThreadEndPosition = (i + 1) != threadNum ? ((i + 1)
						* blockSize - 1) : fileSize;
				FileDownloadThread fdt = new FileDownloadThread(url, saveFile,
						i * blockSize, curThreadEndPosition);
				fdt.setName("thread" + i);
				fdt.start();
				fds[i] = fdt;
			}
			/**
			 * 获取数据,更新UI,直到所有下载线程都下载完成。
			 */
			boolean finished = false;
			// 开始时间,放在循环外,求解的usedTime就是总时间
			long startTime = System.currentTimeMillis();
			while (!finished) {
				downloadSize = 0;
				finished = true;
				for (int i = 0; i < fds.length; i++) {
					downloadSize += fds[i].getDownloadSize();
					if (!fds[i].isFinished()) {
						finished = false;
					}
				}
				downloadPercent = (downloadSize * 100) / fileSize;
				curTime = System.currentTimeMillis();
				System.out.println("curTime = " + curTime + " downloadSize = "
						+ downloadSize + " usedTime "
						+ (int) ((curTime - startTime) / 1000));
				usedTime = (int) ((curTime - startTime) / 1000);

				if (usedTime == 0)
					usedTime = 1;
				downloadSpeed = (downloadSize / usedTime) / 1024;
				sleep(1000);/* 1秒钟刷新一次界面 */
				sendMsg(FileUtil.updateDownloadMeg);
			}
			Log.e(TAG, "下载完成");
			completed = true;
			sendMsg(FileUtil.endDownloadMeg);
		} catch (Exception e) {
			Log.e(TAG, "multi file error  Exception  " + e.getMessage());
			e.printStackTrace();
		}
		super.run();
	}

	/**
	 * 得到文件的大小
	 * 
	 * @return
	 */
	public int getFileSize() {
		return this.fileSize;
	}

	/**
	 * 得到已经下载的数量
	 * 
	 * @return
	 */
	public int getDownloadSize() {
		return this.downloadSize;
	}

	/**
	 * 获取下载百分比
	 * 
	 * @return
	 */
	public int getDownloadPercent() {
		return this.downloadPercent;
	}

	/**
	 * 获取下载速度
	 * 
	 * @return
	 */
	public int getDownloadSpeed() {
		return this.downloadSpeed;
	}

	/**
	 * 修改默认线程数
	 * 
	 * @param threadNum
	 */
	public void setThreadNum(int threadNum) {
		this.threadNum = threadNum;
	}

	/**
	 * 分块下载完成的标志
	 * 
	 * @return
	 */
	public boolean isCompleted() {
		return this.completed;
	}

	@Override
	public String toString() {
		return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize="
				+ fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo
				+ ", savePath=" + savePath + "]";
	}

	/**
	 * 发送消息,用户提示
	 * */
	private void sendMsg(int what) {
		Message msg = new Message();
		msg.what = what;
		handler.sendMessage(msg);
	}
}



3.Activity类
package com.young.download;

import java.io.File;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.young.download.factory.MultiThreadDownload;
import com.young.download.util.FileUtil;

public class MainActivity extends Activity implements OnClickListener {
	protected static final String TAG = "MainActivity";
	private Button button;
	private ProgressBar pb;
	// 需要下载的文件
	private String url = "http://gdown.baidu.com/data/wisegame/3c00add7144d3915/kugouyinle.apk";
	private MultiThreadDownload mUpdateUIThread = null;

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		button = (Button) this.findViewById(R.id.button);
		button.setOnClickListener(this);
		pb = (ProgressBar) this.findViewById(R.id.pb);

		mUpdateUIThread = new MultiThreadDownload(handler, url,
				FileUtil.setMkdir(this) + File.separator);

	}

	@Override
	public void onClick(View v) {
		mUpdateUIThread.start();
	}
	// 对返回的数据进行处理
	private Handler handler = new Handler() {
		@Override
		public void handleMessage(Message msg) {
			switch (msg.what) {
			case FileUtil.startDownloadMeg:
				// 设置进度条中最大的值是文件的大小
				pb.setMax(mUpdateUIThread.getFileSize()); 
				break;
			case FileUtil.updateDownloadMeg:
				if (!mUpdateUIThread.isCompleted()) // 下载
				{
					Log.e(TAG, "已下载:" + mUpdateUIThread.getDownloadSize());
					pb.setProgress(mUpdateUIThread.getDownloadSize());
					button.setText("下载速度:" + mUpdateUIThread.getDownloadSpeed()
							+ "k/秒       下载百分比"
							+ mUpdateUIThread.getDownloadPercent() + "%");
				} else {
					button.setText("下载完成");
				}
				break;
			case FileUtil.endDownloadMeg:
				Toast.makeText(MainActivity.this, "下载完成,马上安装",
						Toast.LENGTH_SHORT).show();
				// 对下载的APK文件进行安装
				String filename = FileUtil.getFileName(url);
				String str = "/myfile/" + filename;
				// 文件的全路径
				String fileName = Environment.getExternalStorageDirectory()
						+ str;
				Intent intent = new Intent(Intent.ACTION_VIEW);
				// 设置intent的data和Type属性。 
				intent.setDataAndType(Uri.fromFile(new File(fileName)),
						"application/vnd.android.package-archive");
				// 跳转到安装页面
				startActivity(intent);
				break;
			}
			super.handleMessage(msg);
		}
	};
}









你可能感兴趣的:(android 多线程下载文件案例)