zoukankan      html  css  js  c++  java
  • 多线程下载 显示进度 速度(转)

    功能要求:从网络下载一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());
        }
        
        @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类进行写入操作。

    转载地址:http://blog.csdn.net/jiantao_yang/article/details/8433905

  • 相关阅读:
    【bzoj1499】[NOI2005]瑰丽华尔兹 【单调队列优化dp】
    【poj3709】K-Anonymous Sequence 【斜率优化dp】
    【bzoj4566】[Haoi2016]找相同字符【后缀自动机】
    【Play】蜂鸣器音乐 校歌
    【poj2373】Dividing the Path【单调队列优化dp】
    【bzoj2010】SubString【后缀自动机+LCT】
    【bzoj1047】[HA蛤OI2007]理想的正方形【单调队列】
    【poj1743】Musical Theme【后缀数组】
    【bzoj4293】[PA2015]Siano【线段树】
    【bzoj4553】[Tjoi2016&Heoi2016]序列【树套树 树状数组套平衡树】
  • 原文地址:https://www.cnblogs.com/yinliang/p/5197418.html
Copyright © 2011-2022 走看看