多线程下载 显示进度 速度(转)

功能要求:从网络下载一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

原文地址:https://www.cnblogs.com/yinliang/p/5197418.html