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

简介:

http://blog.csdn.net/JianTao_Yang/article/details/8433905

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

运行效果图:

工程结构图:

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

主要代码:

 

[java]  view plain copy
  1. /** 
  2.  *多线程下载,UI更新类  
  3.  *@author young 
  4.  * */  
  5. public class MultiThreadDownload extends Thread{  
  6.     private static final String TAG = "MultiThreadDownload";  
  7.     /**每一个线程需要下载的大小 */  
  8.     private int blockSize;  
  9.     /*** 线程数量<br> 默认为5个线程下载*/  
  10.     private int threadNum = 5;  
  11.     /*** 文件大小 */  
  12.     private int fileSize;  
  13.     /** * 已经下载多少 */  
  14.     private int downloadSize;  
  15.     /**文件的url,线程编号,文件名称*/  
  16.     private String UrlStr,ThreadNo,fileName;  
  17.     /***保存的路径*/  
  18.     private String savePath;  
  19.     /**下载的百分比*/  
  20.     private int downloadPercent = 0;  
  21.     /**下载的 平均速度*/  
  22.     private int downloadSpeed = 0;  
  23.     /**下载用的时间*/  
  24.     private int usedTime = 0;  
  25.     /**当前时间*/  
  26.     private long curTime;  
  27.     /**是否已经下载完成*/  
  28.     private boolean completed = false;  
  29.     private Handler handler ;  
  30.     /** 
  31.      * 下载的构造函数   
  32.      * @param url  请求下载的URL 
  33.      * @param handler   UI更新使用 
  34.      * @param savePath  保存文件的路径 
  35.      */  
  36.     public MultiThreadDownload(Handler handler,String url,String savePath)  
  37.     {  
  38.         this.handler = handler;  
  39.         this.UrlStr = url;  
  40.         this.savePath = savePath;  
  41.         Log.e(TAG, toString());  
  42.     }  
  43.       
  44.     @Override  
  45.     public void run() {  
  46.           
  47.         FileDownloadThread[] fds = new FileDownloadThread[threadNum];//设置线程数量  
  48.         try {  
  49.             URL url = new URL(UrlStr);  
  50.             URLConnection conn = url.openConnection();  
  51.             fileSize = conn.getContentLength();  
  52.               
  53.             this.fileName = FileUtil.getFileName(UrlStr);  
  54.             //只创建一个文件,saveFile下载内容  
  55.             File saveFile = new File(savePath+"/"+fileName);  
  56.             Log.e(TAG, "文件一共:"+fileSize+" savePath "+savePath+"  fileName  "+fileName);  
  57.               
  58.             RandomAccessFile accessFile = new RandomAccessFile(saveFile,"rwd");  
  59.             //设置本地文件的长度和下载文件相同     
  60.             accessFile.setLength(fileSize);    
  61.             accessFile.close();  
  62.             //Handler更新UI,发送消息  
  63.             sendMsg(FileUtil.startDownloadMeg);  
  64.             //每块线程下载数据  
  65.             blockSize = ((fileSize%threadNum)==0)?(fileSize/threadNum):(fileSize/threadNum+1);  
  66.             Log.e(TAG, "每个线程分别下载 :"+blockSize);  
  67.               
  68.             for (int i = 0; i < threadNum; i++) {  
  69.                 int curThreadEndPosition = (i+1)!=threadNum ? ((i+1)*blockSize-1) : fileSize;  
  70.                 FileDownloadThread fdt = new FileDownloadThread(url, saveFile, i*blockSize, curThreadEndPosition);  
  71.                 fdt.setName("thread"+i);  
  72.                 fdt.start();  
  73.                 fds[i]=fdt;  
  74.             }  
  75.             /** 
  76.              * 获取数据,更新UI,直到所有下载线程都下载完成。 
  77.              */  
  78.             boolean finished = false;  
  79.             //开始时间,放在循环外,求解的usedTime就是总时间  
  80.             long startTime = System.currentTimeMillis();  
  81.             while(!finished)  
  82.             {  
  83.                 downloadSize = 0;  
  84.                 finished = true;  
  85.                 for (int i = 0; i < fds.length; i++) {  
  86.                     downloadSize+= fds[i].getDownloadSize();  
  87.                     if(!fds[i].isFinished())  
  88.                     {  
  89.                         finished = false;  
  90.                     }  
  91.                 }  
  92.                 downloadPercent = (downloadSize*100)/fileSize;  
  93.                 curTime = System.currentTimeMillis();  
  94.                 System.out.println("curTime = "+curTime+" downloadSize = "+downloadSize+" usedTime "+(int) ((curTime-startTime)/1000));  
  95.                 usedTime = (int) ((curTime-startTime)/1000);  
  96.                   
  97.                 if(usedTime==0)usedTime = 1;    
  98.                 downloadSpeed = (downloadSize/usedTime)/1024;  
  99.                 sleep(1000);/*1秒钟刷新一次界面*/  
  100.                 sendMsg(FileUtil.updateDownloadMeg);  
  101.             }  
  102.             Log.e(TAG, "下载完成");  
  103.             completed = true;  
  104.             sendMsg(FileUtil.endDownloadMeg);  
  105.         } catch (Exception e) {  
  106.             Log.e(TAG, "multi file error  Exception  "+e.getMessage());  
  107.             e.printStackTrace();  
  108.         }  
  109.         super.run();  
  110.     }  
  111.     /** 
  112.      * 得到文件的大小 
  113.      * @return 
  114.      */  
  115.     public int getFileSize()  
  116.     {  
  117.         return this.fileSize;  
  118.     }  
  119.     /** 
  120.      * 得到已经下载的数量 
  121.      * @return 
  122.      */  
  123.     public int getDownloadSize()  
  124.     {  
  125.         return this.downloadSize;  
  126.     }  
  127.     /** 
  128.      * 获取下载百分比 
  129.      * @return 
  130.      */  
  131.     public int getDownloadPercent(){  
  132.         return this.downloadPercent;  
  133.     }  
  134.    /** 
  135.     * 获取下载速度 
  136.     * @return 
  137.     */  
  138.     public int getDownloadSpeed(){  
  139.         return this.downloadSpeed;  
  140.     }  
  141.     /** 
  142.      * 修改默认线程数 
  143.      * @param threadNum 
  144.      */  
  145.     public void setThreadNum(int threadNum){  
  146.         this.threadNum = threadNum;  
  147.     }  
  148.     /** 
  149.      * 分块下载完成的标志 
  150.      * @return 
  151.      */  
  152.     public boolean isCompleted(){  
  153.         return this.completed;  
  154.     }  
  155.     @Override  
  156.     public String toString() {  
  157.         return "MultiThreadDownload [threadNum=" + threadNum + ", fileSize="  
  158.                 + fileSize + ", UrlStr=" + UrlStr + ", ThreadNo=" + ThreadNo  
  159.                 + ", savePath=" + savePath + "]";  
  160.     }  
  161.       
  162.     /** 
  163.      * 发送消息,用户提示 
  164.      * */  
  165.     private void sendMsg(int what)  
  166.     {  
  167.         Message msg = new Message();  
  168.         msg.what = what;  
  169.         handler.sendMessage(msg);  
  170.     }  

 下载类:

[java]  view plain copy
  1. public class FileDownloadThread extends Thread{  
  2.     private static final String TAG = "FileDownloadThread";  
  3.     /**缓冲区 */  
  4.     private static final int BUFF_SIZE = 1024;  
  5.     /**需要下载的URL*/  
  6.     private URL url;  
  7.     /**缓存的FIle*/  
  8.     private File file;  
  9.     /**开始位置*/  
  10.     private int startPosition;  
  11.     /**结束位置*/  
  12.     private int endPosition;  
  13.     /**当前位置*/  
  14.     private int curPosition;  
  15.     /**完成*/  
  16.     private boolean finished = false;  
  17.     /**已经下载多少*/  
  18.     private int downloadSize = 0;  
  19.       
  20.     /*** 
  21.      * 分块文件下载,可以创建多线程模式 
  22.      * @param url   下载的URL 
  23.      * @param file  下载的文件 
  24.      * @param startPosition 开始位置 
  25.      * @param endPosition   结束位置 
  26.      */  
  27.     public FileDownloadThread(URL url, File file, int startPosition,  
  28.             int endPosition) {  
  29.         this.url = url;  
  30.         this.file = file;  
  31.         this.startPosition = startPosition;  
  32.         this.curPosition = startPosition;  
  33.         this.endPosition = endPosition;  
  34.         Log.e(TAG, toString());  
  35.     }  
  36.       
  37.     @Override  
  38.     public void run() {  
  39.         BufferedInputStream bis = null;  
  40.         RandomAccessFile rAccessFile = null;  
  41.         byte[] buf = new byte[BUFF_SIZE];  
  42.         URLConnection conn = null;  
  43.         try {  
  44.             conn = url.openConnection();  
  45.             conn.setConnectTimeout(10000);//设置超时  
  46.             conn.setReadTimeout(10000);  
  47.             conn.setAllowUserInteraction(true);  
  48.                     System.out.println(this.getName()+" startPosition "+startPosition+" endPosition "+endPosition);  
  49.                     conn.setRequestProperty("Range""bytes="+(startPosition)+"-"+endPosition);  //取剩余未下载的  
  50.                     rAccessFile = new RandomAccessFile(file,"rwd");//读写  
  51.                      //设置从什么位置开始写入数据   
  52.                     rAccessFile.seek(startPosition);  
  53.                     bis = new BufferedInputStream(conn.getInputStream(), BUFF_SIZE);  
  54.                     while(curPosition<endPosition)  //当前位置小于结束位置  继续下载  
  55.                     {  
  56.                         int len = bis.read(buf,0,BUFF_SIZE);  
  57.                         if(len==-1)   //下载完成    
  58.                         {   
  59.                             break;  
  60.                         }  
  61.                         rAccessFile.write(buf,0,len);  
  62.                         curPosition = curPosition +len;  
  63.                         if(curPosition > endPosition)  
  64.                         {   //如果下载多了,则减去多余部分  
  65.                             System.out.println("  curPosition > endPosition  !!!!");  
  66.                             int extraLen = curPosition-endPosition;  
  67.                             downloadSize += (len-extraLen+1);  
  68.                         }else{  
  69.                             downloadSize+=len;  
  70.                         }  
  71.                     }  
  72.                     this.finished = true;  //当前阶段下载完成  
  73.             Log.e(TAG, "当前"+this.getName()+"下载完成");  
  74.         } catch (Exception e) {  
  75.             Log.e(TAG, "download error Exception "+e.getMessage());  
  76.             e.printStackTrace();  
  77.         }finally{  
  78.             //关闭流  
  79.             FileUtil.closeInputStream(bis);  
  80.             try {  
  81.                 rAccessFile.close();  
  82.             } catch (IOException e) {  
  83.                 // TODO Auto-generated catch block  
  84.                 Log.e("AccessFile""AccessFile IOException "+e.getMessage());  
  85.             }  
  86.         }  
  87.         super.run();  
  88.     }  
  89.       
  90.     /** 
  91.      * 是否完成当前段下载完成 
  92.      * @return 
  93.      */  
  94.     public boolean isFinished() {  
  95.         return finished;  
  96.     }  
  97.     /** 
  98.      * 已经下载多少 
  99.      * @return 
  100.      */  
  101.     public int getDownloadSize() {  
  102.         return downloadSize;  
  103.     }  
  104.   
  105.     @Override  
  106.     public String toString() {  
  107.         return "FileDownloadThread [url=" + url + ", file=" + file  
  108.                 + ", startPosition=" + startPosition + ", endPosition="  
  109.                 + endPosition + ", curPosition=" + curPosition + ", finished="  
  110.                 + finished + ", downloadSize=" + downloadSize + "]";  
  111.     }  


这里面多线程下载是分段下载,创建保存一个文件(之前每个子线程都创建一个子文件,最后整合,发现文件整合有问题,安装失败,原因没找到),子线程分别通过RandomAccessFile类进行写入操作。


相关文章
|
1月前
|
Java 调度 Android开发
构建高效Android应用:探究Kotlin多线程编程
【2月更文挑战第17天】 在现代移动开发领域,性能优化一直是开发者关注的焦点。特别是在Android平台上,合理利用多线程技术可以显著提升应用程序的响应性和用户体验。本文将深入探讨使用Kotlin进行Android多线程编程的策略与实践,旨在为开发者提供系统化的解决方案和性能提升技巧。我们将从基础概念入手,逐步介绍高级特性,并通过实际案例分析如何有效利用Kotlin协程、线程池以及异步任务处理机制来构建一个更加高效的Android应用。
40 4
|
1月前
|
API 数据库 Android开发
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第14天】随着移动设备性能的日益强大,用户对应用程序的响应速度和流畅性要求越来越高。在Android开发中,合理利用多线程技术是提升应用性能的关键手段之一。Kotlin作为一种现代的编程语言,其协程特性为开发者提供了更为简洁高效的多线程处理方式。本文将深入探讨使用Kotlin进行Android多线程编程的最佳实践,包括协程的基本概念、优势以及在实际项目中的应用场景和性能优化技巧,旨在帮助开发者构建更加高效稳定的Android应用。
|
3月前
|
Java 调度 数据库
Android 性能优化: 如何进行多线程编程以提高应用性能?
Android 性能优化: 如何进行多线程编程以提高应用性能?
47 0
|
4月前
|
XML Java Android开发
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
Android App开发网络通信中使用okhttp下载和上传图片、文件讲解及实战(超详细实现用户注册信息上传 附源码)
138 0
|
10天前
|
Java API 调度
安卓多线程和并发处理:提高应用效率
【4月更文挑战第13天】本文探讨了安卓应用中多线程和并发处理的优化方法,包括使用Thread、AsyncTask、Loader、IntentService、JobScheduler、WorkManager以及线程池。此外,还介绍了RxJava和Kotlin协程作为异步编程工具。理解并恰当运用这些技术能提升应用效率,避免UI卡顿,确保良好用户体验。随着安卓技术发展,更高级的异步处理工具将助力开发者构建高性能应用。
|
21天前
|
安全 Linux API
Android进程与线程
Android进程与线程
18 0
|
1月前
|
Shell 开发工具 Android开发
ADB 下载、安装及使用教程:让你更好地管理 Android 设备
ADB 下载、安装及使用教程:让你更好地管理 Android 设备
488 2
|
1月前
|
Java Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【2月更文挑战第17天】 随着移动设备性能的不断提升,用户对应用的响应速度和稳定性要求越来越高。在Android开发中,Kotlin语言以其简洁、安全的特点受到开发者青睐。然而,面对复杂的多线程任务,如何有效利用Kotlin进行优化,以提升应用性能,是本文探讨的重点。通过分析Kotlin并发工具的使用场景与限制,结合实例演示其在Android开发中的实践,旨在为开发者提供实用的多线程处理指南。
|
1月前
|
Android开发 对象存储
OSS对象储存android开发进行下载到本地文件时异步操作失效
android vivo80使用官方示例代码进行文件下载,但是使用oss.asyncGetObject(get, new OSSCompletedCallback<GetObjectRequest, GetObjectResult>()时onSuccess和onFailure不执行
|
4月前
|
XML Java 调度
Android App网络通信中通过runOnUiThread快速操纵界面以及利用线程池Executor调度异步任务实战(附源码 简单易懂)
Android App网络通信中通过runOnUiThread快速操纵界面以及利用线程池Executor调度异步任务实战(附源码 简单易懂)
30 0