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

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

时间: 2024-10-05 15:54:12

多线程下载 显示进度 速度(转)的相关文章

赵雅智_android多线程下载带进度条

progressBar说明 在某些操作的进度中的可视指示器,为用户呈现操作的进度,还它有一个次要的进度条,用来显示中间进度,如在流媒体播放的缓冲区的进度.一个进度条也可不确定其进度.在不确定模式下,进度条显示循环动画.这种模式常用于应用程序使用任务的长度是未知的. XML重要属性 android:progressBarStyle:默认进度条样式 android:progressBarStyleHorizontal:水平样式 progressBar重要方法 getMax():返回这个进度条的范围的

关于多线程执行显示进度条的实例(转)&amp;&amp;线程间操作无效: 从不是创建控件“rtxtEntryNO”的线程访问它。

关于多线程执行显示进度条的实例! 之前回答了一篇关于怎么在线程中操作进度条的帖子,估计有人看的不是很明白今天没事,写了一个小小的实例,很简单,就2个文件权当抛砖引玉,希望有更好解决方案的人发表一下意见 界面上2个控件,一个按钮和一个进度条using System;using System.Threading;using System.Windows.Forms; namespace WindowsFormsApplication2{    public partial class Form1 :

ftp下载显示进度

经常用到ftp get命令下载东西,但是遇到大的文件不知道是挂了还是在运行,要是能显示就好了,于是就有了下文... 注: 红色 字体是我敲击的命令 "#" 是注释语 [[email protected] server]# ftp 10.2.1.67     #登录服务器Connected to 10.2.1.67.220-FileZilla Server version 0.9.34 beta220-written by Tim Kosse ([email protected])220

Android 网络学习之使用多线程下载,支持断点续传

既然本节是学习如何使用多线程下载,那我们先要明白什么是多线程下载,在搞明白什么是多线程下载之前,需要先知道什么是单线程下载. 上图就是说明了单线程下载的原来,因此单线程下载速度很慢,因为只有一个任务在干活. 这样的话,3个线程下载一个文件,总比1个线程一个文件的速度要快.所以多线程下载数据的速度就快. 既然知道了多线程的下载原理,那我们就分析多个线程是如何下载数据,以及如何保存数据的. 知道多线程下载的原理,以及每个线程如何存放数据后,那就开始写代码. 1: 当然先要获取该数据的大小了,这样才知

VC下载文件 + 显示进度条

在codeproject里找了许久,发现这样一个VC下载文件并显示进度条的源码,于是添加了些中文注释: 1.下载线程函数: [cpp] view plain copy print? UINT DownloadFile(LPVOID pParam) { CWnd*           pwnd = AfxGetMainWnd(); CProgressCtrl*  m_Prog = (CProgressCtrl*)pwnd->GetDlgItem(IDC_PROGRESS1); CButton*  

Android中多线程下载列表的封装实现(含进度反馈)

来源:http://blog.csdn.net/u011638883/article/details/17347015 实现了一下Android中的文件多线程下载模块,支持自定义线程数.断点续传.下载任务的删除,添加等功能,这里封装了一下,功能已全部实现.不过由于使用的是最简单的手动线程数组及消息通知实现,可能还存在某些小问题.笔者会在后面的使用过程中再进行优化完善.先看一下程序测试效果,这里指定了5个下载任务,以及2个下载线程,具体如下: 要运行以上Demo需要自己搭建服务器,和简单,只需要把

【黑马Android】(07)多线程下载的原理/开源项目xutils/显示意图/隐式意图/人品计算器/开启activity获取返回值

多线程下载的原理 司马光砸缸,多开几个小水管,抢救小朋友. import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import

VC下载文件显示进度条

VC下载文件显示进度条 逗比汪星人2009-09-18上传 by Koma http://blog.csd.net/wangningyu http://download.csdn.net/detail/wangningyu/1674247

Retrofit2文件上传下载及其进度显示

序 前面一篇文章介绍了Retrofit2的基本使用,这篇文章接着介绍使用Retrofit2实现文件上传和文件下载,以及上传下载过程中如何实现进度的显示. 文件上传 定义接口 1 2 3 @Multipart @POST("fileService") Call<User> uploadFile(@Part MultipartBody.Part file); 构造请求体上传 1 2 3 4 5 File file = new File(filePath); RequestBod