您的位置:首页 > 移动开发 > Android开发

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

2015-10-13 14:34 465 查看
http://blog.csdn.net/JianTao_Yang/article/details/8433905

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

运行效果图:



工程结构图:



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

主要代码:

 

[java] view
plaincopy

/** 

 *多线程下载,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);  

    }  

 下载类:

[java] view
plaincopy

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类进行写入操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: