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

来源:互联网 发布:smtp.ym.163.com 端口 编辑:程序博客网 时间:2024/05/16 04:36

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

运行效果图:

工程结构图:

很简单,就一个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());}@Overridepublic 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;}@Overridepublic 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());}@Overridepublic 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 blockLog.e("AccessFile", "AccessFile IOException "+e.getMessage());}}super.run();}/** * 是否完成当前段下载完成 * @return */public boolean isFinished() {return finished;}/** * 已经下载多少 * @return */public int getDownloadSize() {return downloadSize;}@Overridepublic String toString() {return "FileDownloadThread [url=" + url + ", file=" + file+ ", startPosition=" + startPosition + ", endPosition="+ endPosition + ", curPosition=" + curPosition + ", finished="+ finished + ", downloadSize=" + downloadSize + "]";}


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


demo下载链接

原创粉丝点击