android 多线程下载 显示进度 速度

功能要求:从网络下载一APK应用,显示下载速度、进度,并安装应用。

运行效果图:

android 多线程下载 显示进度 速度_第1张图片

工程结构图:

android 多线程下载 显示进度 速度_第2张图片

很简单,就一个activity,一个更新UI的线程,一个下载线程加个文件处理类

主要代码:

 

/**
 *多线程下载,UI更新类 
 *@author young
 * */
public class MultiThreadDownload extends Thread{
	private static final String TAG = "MultiThreadDownload";
	/**每一个线程需要下载的大小 */
	private int blockSize;
	/*** 线程数量<br> 默认为5个线程下载*/
	private int threadNum = 5;
	/*** 文件大小 */
	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);
	}

 下载类:

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{
			//关闭流
			FileUtil.closeInputStream(bis);
			try {
				rAccessFile.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				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 + "]";
	}


这里面多线程下载是分段下载,创建保存一个文件,子线程分别通过RandomAccessFile类进行写入操作。


demo下载链接

你可能感兴趣的:(多线程,android,File)