博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android 实现网络多线程APK文件下载
阅读量:7240 次
发布时间:2019-06-29

本文共 10101 字,大约阅读时间需要 33 分钟。

(转自:)

实现原理

(1)首先获得下载文件的长度,然后设置本地文件的长度。

(2)根据文件长度和线程数计算每条线程下载的数据长度和下载位置。

如:文件的长度为6M,线程数为3,那么,每条线程下载的数据长度为2M,每条线程开始下载的位置如下图所示:

例如10M大小,使用3个线程来下载,

线程下载的数据长度   (10%3 == 0 ? 10/3:10/3+1) ,第1,2个线程下载长度是4M,第三个线程下载长度为2M

下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?

之前练习时的一个demo,不多说了,直接上代码吧,有关断点续传,需要使用数据库,不再加了,网上有很多成熟的项目可以直接用。

实例

MainApp:

1 package com.amos.app;  2   3 import java.io.File;  4 import java.io.IOException;  5 import java.net.MalformedURLException;  6 import java.net.URL;  7 import java.net.URLConnection;  8 import com.amos.download.R;  9 import android.annotation.SuppressLint; 10 import android.app.Activity; 11 import android.os.Bundle; 12 import android.os.Environment; 13 import android.os.Handler; 14 import android.os.Message; 15 import android.util.Log; 16 import android.view.View; 17 import android.view.View.OnClickListener; 18 import android.widget.ProgressBar; 19 import android.widget.TextView; 20 import android.widget.Toast; 21  22 /** 23  * @author yangxiaolong 24  * @2014-5-6 25  */ 26 public class MainApp extends Activity implements OnClickListener { 27  28     private static final String TAG = MainApp.class.getSimpleName(); 29  30     /** 显示下载进度TextView */ 31     private TextView mMessageView; 32     /** 显示下载进度ProgressBar */ 33     private ProgressBar mProgressbar; 34  35     @Override 36     protected void onCreate(Bundle savedInstanceState) { 37         super.onCreate(savedInstanceState); 38         setContentView(R.layout.progress_activity); 39         findViewById(R.id.download_btn).setOnClickListener(this); 40         mMessageView = (TextView) findViewById(R.id.download_message); 41         mProgressbar = (ProgressBar) findViewById(R.id.download_progress); 42     } 43  44     @Override 45     public void onClick(View v) { 46         if (v.getId() == R.id.download_btn) { 47             doDownload(); 48         } 49     } 50  51     /** 52      * 使用Handler更新UI界面信息 53      */ 54     @SuppressLint("HandlerLeak") 55     Handler mHandler = new Handler() { 56         @Override 57         public void handleMessage(Message msg) { 58  59             mProgressbar.setProgress(msg.getData().getInt("size")); 60  61             float temp = (float) mProgressbar.getProgress() 62                     / (float) mProgressbar.getMax(); 63  64             int progress = (int) (temp * 100); 65             if (progress == 100) { 66                 Toast.makeText(MainApp.this, "下载完成!", Toast.LENGTH_LONG).show(); 67             } 68             mMessageView.setText("下载进度:" + progress + " %"); 69  70         } 71     }; 72  73     /** 74      * 下载准备工作,获取SD卡路径、开启线程 75      */ 76     private void doDownload() { 77         // 获取SD卡路径 78         String path = Environment.getExternalStorageDirectory() 79                 + "/amosdownload/"; 80         File file = new File(path); 81         // 如果SD卡目录不存在创建 82         if (!file.exists()) { 83             file.mkdir(); 84         } 85         // 设置progressBar初始化 86         mProgressbar.setProgress(0); 87  88         // 简单起见,我先把URL和文件名称写死,其实这些都可以通过HttpHeader获取到 89         String downloadUrl = "http://gdown.baidu.com/data/wisegame/91319a5a1dfae322/baidu_16785426.apk"; 90         String fileName = "baidu_16785426.apk"; 91         int threadNum = 5; 92         String filepath = path + fileName; 93         Log.d(TAG, "download file  path:" + filepath); 94         downloadTask task = new downloadTask(downloadUrl, threadNum, filepath); 95         task.start(); 96     } 97  98     /** 99      * 多线程文件下载100      * 101      * @author yangxiaolong102      * @2014-8-7103      */104     class downloadTask extends Thread {105         private String downloadUrl;// 下载链接地址106         private int threadNum;// 开启的线程数107         private String filePath;// 保存文件路径地址108         private int blockSize;// 每一个线程的下载量109 110         public downloadTask(String downloadUrl, int threadNum, String fileptah) {111             this.downloadUrl = downloadUrl;112             this.threadNum = threadNum;113             this.filePath = fileptah;114         }115 116         @Override117         public void run() {118 119             FileDownloadThread[] threads = new FileDownloadThread[threadNum];120             try {121                 URL url = new URL(downloadUrl);122                 Log.d(TAG, "download file http path:" + downloadUrl);123                 URLConnection conn = url.openConnection();124                 // 读取下载文件总大小125                 int fileSize = conn.getContentLength();126                 if (fileSize <= 0) {127                     System.out.println("读取文件失败");128                     return;129                 }130                 // 设置ProgressBar最大的长度为文件Size131                 mProgressbar.setMax(fileSize);132 133                 // 计算每条线程下载的数据长度134                 blockSize = (fileSize % threadNum) == 0 ? fileSize / threadNum135                         : fileSize / threadNum + 1;136 137                 Log.d(TAG, "fileSize:" + fileSize + "  blockSize:");138 139                 File file = new File(filePath);140                 for (int i = 0; i < threads.length; i++) {141                     // 启动线程,分别下载每个线程需要下载的部分142                     threads[i] = new FileDownloadThread(url, file, blockSize,143                             (i + 1));144                     threads[i].setName("Thread:" + i);145                     threads[i].start();146                 }147 148                 boolean isfinished = false;149                 int downloadedAllSize = 0;150                 while (!isfinished) {151                     isfinished = true;152                     // 当前所有线程下载总量153                     downloadedAllSize = 0;154                     for (int i = 0; i < threads.length; i++) {155                         downloadedAllSize += threads[i].getDownloadLength();156                         if (!threads[i].isCompleted()) {157                             isfinished = false;158                         }159                     }160                     // 通知handler去更新视图组件161                     Message msg = new Message();162                     msg.getData().putInt("size", downloadedAllSize);163                     mHandler.sendMessage(msg);164                     // Log.d(TAG, "current downloadSize:" + downloadedAllSize);165                     Thread.sleep(1000);// 休息1秒后再读取下载进度166                 }167                 Log.d(TAG, " all of downloadSize:" + downloadedAllSize);168 169             } catch (MalformedURLException e) {170                 e.printStackTrace();171             } catch (IOException e) {172                 e.printStackTrace();173             } catch (InterruptedException e) {174                 e.printStackTrace();175             }176 177         }178     }179 180 }

FileDownloadThread:

1 package com.amos.app;  2   3 import java.io.BufferedInputStream;  4 import java.io.File;  5 import java.io.IOException;  6 import java.io.RandomAccessFile;  7 import java.net.URL;  8 import java.net.URLConnection;  9 import android.util.Log; 10  11 /** 12  * 文件下载类 13  *  14  * @author yangxiaolong 15  * @2014-5-6 16  */ 17 public class FileDownloadThread extends Thread { 18  19     private static final String TAG = FileDownloadThread.class.getSimpleName(); 20  21     /** 当前下载是否完成 */ 22     private boolean isCompleted = false; 23     /** 当前下载文件长度 */ 24     private int downloadLength = 0; 25     /** 文件保存路径 */ 26     private File file; 27     /** 文件下载路径 */ 28     private URL downloadUrl; 29     /** 当前下载线程ID */ 30     private int threadId; 31     /** 线程下载数据长度 */ 32     private int blockSize; 33  34     /** 35      *  36      * @param url:文件下载地址 37      * @param file:文件保存路径 38      * @param blocksize:下载数据长度 39      * @param threadId:线程ID 40      */ 41     public FileDownloadThread(URL downloadUrl, File file, int blocksize, 42             int threadId) { 43         this.downloadUrl = downloadUrl; 44         this.file = file; 45         this.threadId = threadId; 46         this.blockSize = blocksize; 47     } 48  49     @Override 50     public void run() { 51  52         BufferedInputStream bis = null; 53         RandomAccessFile raf = null; 54  55         try { 56             URLConnection conn = downloadUrl.openConnection(); 57             conn.setAllowUserInteraction(true); 58  59             int startPos = blockSize * (threadId - 1);//开始位置 60             int endPos = blockSize * threadId - 1;//结束位置 61             //设置当前线程下载的起点、终点 62             conn.setRequestProperty("Range", "bytes=" + startPos + "-" + endPos); 63             System.out.println(Thread.currentThread().getName() + "  bytes=" 64                     + startPos + "-" + endPos); 65  66             byte[] buffer = new byte[1024]; 67             bis = new BufferedInputStream(conn.getInputStream()); 68  69             raf = new RandomAccessFile(file, "rwd"); 70             raf.seek(startPos); 71             int len; 72             while ((len = bis.read(buffer, 0, 1024)) != -1) { 73                 raf.write(buffer, 0, len); 74                 downloadLength += len; 75             } 76             isCompleted = true; 77             Log.d(TAG, "current thread task has finished,all size:" 78                     + downloadLength); 79  80         } catch (IOException e) { 81             e.printStackTrace(); 82         } finally { 83             if (bis != null) { 84                 try { 85                     bis.close(); 86                 } catch (IOException e) { 87                     e.printStackTrace(); 88                 } 89             } 90             if (raf != null) { 91                 try { 92                     raf.close(); 93                 } catch (IOException e) { 94                     e.printStackTrace(); 95                 } 96             } 97         } 98     } 99 100     /**101      * 线程文件是否下载完毕102      */103     public boolean isCompleted() {104         return isCompleted;105     }106 107     /**108      * 线程下载文件长度109      */110     public int getDownloadLength() {111         return downloadLength;112     }113 114 }

补充:.xml文件:

1 
2
7 8
18 19
29 30
39 40

 

效果图:

转载地址:http://pjybm.baihongyu.com/

你可能感兴趣的文章
13.ng-value
查看>>
8天掌握EF的Code First开发系列之动手写第一个Code First应用
查看>>
【Django】 积累
查看>>
iOS App的加固保护原理
查看>>
测试左移和测试右移
查看>>
云开发初探 —— 更简便的小程序开发模式
查看>>
CSharpGL(49)试水OpenGL软实现
查看>>
Centos7安装Tomcat并部署DubboAdmin的War包并配置自动启动
查看>>
Linux嵌入式时区修改
查看>>
[ACM] HDU 5024 Wang Xifeng&#39;s Little Plot (构造,枚举)
查看>>
微软小子Kie
查看>>
JQuery的extend扩展方法
查看>>
Ubuntu10下MySQL搭建Amoeba_分片升级版
查看>>
ClassCastException[转贴]
查看>>
MySQL vs.MongoDB 各有胜负!
查看>>
寻找最大的K个数,Top K问题的堆实现
查看>>
DDD:在基于关系数据库的领域,聚合的边界等于并发管理的边界。
查看>>
新浪iphone微博小结
查看>>
[置顶] STM32移植contiki进阶之三(中):timer 中文版
查看>>
走进C++程序世界-----继承和派生(2)
查看>>