首页 > 系统 > Android > 正文

Android实现多线程下载文件的方法

2019-10-24 20:35:41
字体:
来源:转载
供稿:网友

这篇文章主要介绍了Android实现多线程下载文件的方法,以实例形式较为详细的分析了Android多线程文件传输及合并等操作的相关技巧,具有一定参考借鉴价值,需要的朋友可以参考下

本文实例讲述了Android实现多线程下载文件的方法。分享给大家供大家参考。具体如下:

多线程下载大概思路就是通过Range 属性实现文件分段,然后用RandomAccessFile 来读写文件,最终合并为一个文件

首先看下效果图:

Android实现多线程下载文件的方法

创建工程 ThreadDemo

首先布局文件 threaddemo.xml

 

 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  3. android:orientation="vertical" 
  4. android:layout_width="fill_parent" 
  5. android:layout_height="fill_parent" 
  6. >  
  7. <TextView 
  8. android:layout_width="fill_parent" 
  9. android:layout_height="wrap_content" 
  10. android:text="下载地址" 
  11. />  
  12. <TextView 
  13. android:id="@+id/downloadurl" 
  14. android:layout_width="fill_parent" 
  15. android:layout_height="wrap_content" 
  16. android:lines="5" 
  17. />  
  18. <TextView 
  19. android:layout_width="fill_parent" 
  20. android:layout_height="wrap_content" 
  21. android:text="线程数" 
  22. />  
  23. <EditText 
  24. android:id="@+id/downloadnum" 
  25. android:layout_width="fill_parent" 
  26. android:layout_height="wrap_content" 
  27. />  
  28. <ProgressBar 
  29. android:id="@+id/downloadProgressBar" 
  30. android:layout_width="fill_parent" 
  31. style="?android:attr/progressBarStyleHorizontal" 
  32. android:layout_height="wrap_content" 
  33. />  
  34. <TextView 
  35. android:id="@+id/downloadinfo" 
  36. android:layout_width="fill_parent" 
  37. android:layout_height="wrap_content" 
  38. android:text="下载进度 0" 
  39. />  
  40. <Button 
  41. android:id="@+id/downloadbutton" 
  42. android:layout_width="wrap_content" 
  43. android:layout_height="wrap_content" 
  44. android:text="开始下载" 
  45. />  
  46. </LinearLayout> 

 

 
  1. <?xml version="1.0" encoding="utf-8"?> 
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > 
  3. <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下载地址" /> 
  4. <TextViewandroid:id="@+id/downloadurl"android:layout_width="fill_parent" android:layout_height="wrap_content" android:lines="5"/> 
  5. <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="线程数" /> 
  6. <EditTextandroid:id="@+id/downloadnum"android:layout_width="fill_parent" android:layout_height="wrap_content" /> 
  7. <ProgressBarandroid:id="@+id/downloadProgressBar"android:layout_width="fill_parent" style="?android:attr/progressBarStyleHorizontal" android:layout_height="wrap_content" /> 
  8. <TextViewandroid:id="@+id/downloadinfo"android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="下载进度 0"/> 
  9. <Buttonandroid:id="@+id/downloadbutton"android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="开始下载"/> 
  10. </LinearLayout>  

主界面 Acitivity

 

 
  1. public class ThreadDownloadDemo extends Activity {  
  2. private TextView downloadurl;  
  3. private EditText downloadnum;  
  4. private Button downloadbutton;  
  5. private ProgressBar downloadProgressBar;  
  6. private TextView downloadinfo;  
  7. private int downloadedSize = 0;  
  8. private int fileSize = 0;  
  9. private long downloadtime;  
  10. @Override 
  11. public void onCreate(Bundle savedInstanceState) {  
  12. super.onCreate(savedInstanceState);  
  13. setContentView(R.layout.threaddemo);  
  14. downloadurl = (TextView) findViewById(R.id.downloadurl);  
  15. downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3");  
  16. downloadnum = (EditText) findViewById(R.id.downloadnum);  
  17. downloadinfo = (TextView) findViewById(R.id.downloadinfo);  
  18. downloadbutton = (Button) findViewById(R.id.downloadbutton);  
  19. downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);  
  20. downloadProgressBar.setVisibility(View.VISIBLE);  
  21. downloadProgressBar.setMax(100);  
  22. downloadProgressBar.setProgress(0);  
  23. downloadbutton.setOnClickListener(new OnClickListener() {  
  24. public void onClick(View v) {  
  25. download();  
  26. downloadtime = SystemClock.currentThreadTimeMillis();  
  27. }  
  28. });  
  29. }  
  30. private void download() {  
  31. // 获取SD卡目录  
  32. String dowloadDir = Environment.getExternalStorageDirectory()  
  33. "/threaddemodownload/";  
  34. File file = new File(dowloadDir);  
  35. //创建下载目录  
  36. if (!file.exists()) {  
  37. file.mkdirs();  
  38. }  
  39. //读取下载线程数,如果为空,则单线程下载  
  40. int downloadTN = Integer.valueOf("".equals(downloadnum.getText()  
  41. .toString()) ? "1" : downloadnum.getText().toString());  
  42. String fileName = "hetang.mp3";  
  43. //开始下载前把下载按钮设置为不可用  
  44. downloadbutton.setClickable(false);  
  45. //进度条设为0  
  46. downloadProgressBar.setProgress(0);  
  47. //启动文件下载线程  
  48. new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", Integer  
  49. .valueOf(downloadTN), dowloadDir + fileName).start();  
  50. }  
  51. Handler handler = new Handler() {  
  52. @Override 
  53. public void handleMessage(Message msg) {  
  54. //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息  
  55. int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();  
  56. if (progress == 100) {  
  57. downloadbutton.setClickable(true);  
  58. downloadinfo.setText("下载完成!");  
  59. Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this)  
  60. .setTitle("提示信息")  
  61. .setMessage("下载完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒")  
  62. .setNegativeButton("确定"new DialogInterface.OnClickListener(){  
  63. @Override 
  64. public void onClick(DialogInterface dialog, int which) {  
  65. dialog.dismiss();  
  66. }  
  67. })  
  68. .create();  
  69. mdialog.show();  
  70. else {  
  71. downloadinfo.setText("当前进度:" + progress + "%");  
  72. }  
  73. downloadProgressBar.setProgress(progress);  
  74. }  
  75. };  
  76. public class downloadTask extends Thread {  
  77. private int blockSize, downloadSizeMore;  
  78. private int threadNum = 5;  
  79. String urlStr, threadNo, fileName;  
  80. public downloadTask(String urlStr, int threadNum, String fileName) {  
  81. this.urlStr = urlStr;  
  82. this.threadNum = threadNum;  
  83. this.fileName = fileName;  
  84. }  
  85. @Override 
  86. public void run() {  
  87. FileDownloadThread[] fds = new FileDownloadThread[threadNum];  
  88. try {  
  89. URL url = new URL(urlStr);  
  90. URLConnection conn = url.openConnection();  
  91. //防止返回-1  
  92. InputStream in = conn.getInputStream();  
  93. //获取下载文件的总大小  
  94. fileSize = conn.getContentLength();  
  95. Log.i("bb""======================fileSize:"+fileSize);  
  96. //计算每个线程要下载的数据量  
  97. blockSize = fileSize / threadNum;  
  98. // 解决整除后百分比计算误差  
  99. downloadSizeMore = (fileSize % threadNum);  
  100. File file = new File(fileName);  
  101. for (int i = 0; i < threadNum; i++) {  
  102. Log.i("bb""======================i:"+i);  
  103. //启动线程,分别下载自己需要下载的部分  
  104. FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);  
  105. fdt.setName("Thread" + i);  
  106. fdt.start();  
  107. fds[i] = fdt;  
  108. }  
  109. boolean finished = false;  
  110. while (!finished) {  
  111. // 先把整除的余数搞定  
  112. downloadedSize = downloadSizeMore;  
  113. finished = true;  
  114. for (int i = 0; i < fds.length; i++) {  
  115. downloadedSize += fds[i].getDownloadSize();  
  116. if (!fds[i].isFinished()) {  
  117. finished = false;  
  118. }  
  119. }  
  120. handler.sendEmptyMessage(0);  
  121. //线程暂停一秒  
  122. sleep(1000);  
  123. }  
  124. catch (Exception e) {  
  125. e.printStackTrace();  
  126. }  
  127. }  
  128. }  
  129. }  
  130. public class ThreadDownloadDemo extends Activity { 
  131. private TextView downloadurl; 
  132. private EditText downloadnum; 
  133. private Button downloadbutton; 
  134. private ProgressBar downloadProgressBar; 
  135. private TextView downloadinfo; 
  136. private int downloadedSize = 0; 
  137. private int fileSize = 0; 
  138. private long downloadtime; 
  139. @Overridepublic void onCreate(Bundle savedInstanceState) { 
  140. super.onCreate(savedInstanceState); 
  141. setContentView(R.layout.threaddemo); 
  142. downloadurl = (TextView) findViewById(R.id.downloadurl); 
  143. downloadurl.setText("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3"); 
  144. downloadnum = (EditText) findViewById(R.id.downloadnum); 
  145. downloadinfo = (TextView) findViewById(R.id.downloadinfo); 
  146. downloadbutton = (Button) findViewById(R.id.downloadbutton); 
  147. downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar); 
  148. downloadProgressBar.setVisibility(View.VISIBLE); 
  149. downloadProgressBar.setMax(100); 
  150. downloadProgressBar.setProgress(0); 
  151. downloadbutton.setOnClickListener(new OnClickListener() { 
  152. public void onClick(View v) {download(); 
  153. downloadtime = SystemClock.currentThreadTimeMillis(); 
  154. ); 
  155. private void download() {// 获取SD卡目录 
  156. String dowloadDir = Environment.getExternalStorageDirectory()+ "/threaddemodownload/"
  157. File file = new File(dowloadDir); 
  158. //创建下载目录 
  159. if (!file.exists()) {file.mkdirs(); 
  160. }//读取下载线程数,如果为空,则单线程下载 
  161. int downloadTN = Integer.valueOf("".equals(downloadnum.getText().toString()) ? "1" : downloadnum.getText().toString()); 
  162. String fileName = "hetang.mp3"
  163. //开始下载前把下载按钮设置为不可用 
  164. downloadbutton.setClickable(false); 
  165. //进度条设为0 
  166. downloadProgressBar.setProgress(0); 
  167. //启动文件下载线程 
  168. new downloadTask("http://file16.top100.cn/201105110911/AA5CC27CBE34DEB50A194581D1300881/Special_323149/%E8%8D%B7%E5%A1%98%E6%9C%88%E8%89%B2.mp3", Integer.valueOf(downloadTN), dowloadDir + fileName).start(); 
  169. Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) { 
  170. //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息 
  171. int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue(); 
  172. if (progress == 100) {downloadbutton.setClickable(true); 
  173. downloadinfo.setText("下载完成!"); 
  174. Dialog mdialog = new AlertDialog.Builder(ThreadDownloadDemo.this).setTitle("提示信息").setMessage("下载完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒").setNegativeButton("确定"new DialogInterface.OnClickListener(){@Overridepublic void onClick(DialogInterface dialog, int which) {dialog.dismiss(); 
  175. }}).create(); 
  176. mdialog.show(); 
  177. else { 
  178. downloadinfo.setText("当前进度:" + progress + "%"); 
  179. downloadProgressBar.setProgress(progress); 
  180. };  
  181. public class downloadTask extends Thread {private int blockSize, downloadSizeMore; 
  182. private int threadNum = 5; 
  183. String urlStr, threadNo, fileName; 
  184. public downloadTask(String urlStr, int threadNum, String fileName) { 
  185. this.urlStr = urlStr; 
  186. this.threadNum = threadNum; 
  187. this.fileName = fileName; 
  188. @Overridepublic void run() { 
  189. FileDownloadThread[] fds = new FileDownloadThread[threadNum]; 
  190. try {URL url = new URL(urlStr); 
  191. URLConnection conn = url.openConnection(); 
  192. //防止返回-1 
  193. InputStream in = conn.getInputStream(); 
  194. //获取下载文件的总大小 
  195. fileSize = conn.getContentLength(); 
  196. Log.i("bb""======================fileSize:"+fileSize); 
  197. //计算每个线程要下载的数据量 
  198. blockSize = fileSize / threadNum; 
  199. // 解决整除后百分比计算误差 
  200. downloadSizeMore = (fileSize % threadNum); 
  201. File file = new File(fileName); 
  202. for (int i = 0; i < threadNum; i++) { 
  203. Log.i("bb""======================i:"+i); 
  204. //启动线程,分别下载自己需要下载的部分 
  205. FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1); 
  206. fdt.setName("Thread" + i); 
  207. fdt.start(); 
  208. fds[i] = fdt; 
  209. boolean finished = false
  210. while (!finished) { 
  211. // 先把整除的余数搞定 
  212. downloadedSize = downloadSizeMore; 
  213. finished = true
  214. for (int i = 0; i < fds.length; i++) { 
  215. downloadedSize += fds[i].getDownloadSize(); 
  216. if (!fds[i].isFinished()) { 
  217. finished = false
  218. handler.sendEmptyMessage(0); 
  219. //线程暂停一秒sleep(1000); 
  220. catch (Exception e) { 
  221. e.printStackTrace(); 
  222. }  

这里启动线程将文件分割为几个部分,每一个部分再启动一个线程去下载数据

下载文件的线程

 

 
  1. public class FileDownloadThread extends Thread{  
  2. private static final int BUFFER_SIZE=1024;  
  3. private URL url;  
  4. private File file;  
  5. private int startPosition;  
  6. private int endPosition;  
  7. private int curPosition;  
  8. //标识当前线程是否下载完成  
  9. private boolean finished=false;  
  10. private int downloadSize=0;  
  11. public FileDownloadThread(URL url,File file,int startPosition,int endPosition){  
  12. this.url=url;  
  13. this.file=file;  
  14. this.startPosition=startPosition;  
  15. this.curPosition=startPosition;  
  16. this.endPosition=endPosition;  
  17. }  
  18. @Override 
  19. public void run() {  
  20. BufferedInputStream bis = null;  
  21. RandomAccessFile fos = null;  
  22. byte[] buf = new byte[BUFFER_SIZE];  
  23. URLConnection con = null;  
  24. try {  
  25. con = url.openConnection();  
  26. con.setAllowUserInteraction(true);  
  27. //设置当前线程下载的起止点  
  28. con.setRequestProperty("Range""bytes=" + startPosition + "-" + endPosition);  
  29. Log.i("bb", Thread.currentThread().getName()+" bytes=" + startPosition + "-" + endPosition);  
  30. //使用java中的RandomAccessFile 对文件进行随机读写操作  
  31. fos = new RandomAccessFile(file, "rw");  
  32. //设置写文件的起始位置  
  33. fos.seek(startPosition);  
  34. bis = new BufferedInputStream(con.getInputStream());  
  35. //开始循环以流的形式读写文件  
  36. while (curPosition < endPosition) {  
  37. int len = bis.read(buf, 0, BUFFER_SIZE);  
  38. if (len == -1) {  
  39. break;  
  40. }  
  41. fos.write(buf, 0, len);  
  42. curPosition = curPosition + len;  
  43. if (curPosition > endPosition) {  
  44. downloadSize+=len - (curPosition - endPosition) + 1;  
  45. else {  
  46. downloadSize+=len;  
  47. }  
  48. }  
  49. //下载完成设为true  
  50. this.finished = true;  
  51. bis.close();  
  52. fos.close();  
  53. catch (IOException e) {  
  54. e.printStackTrace();  
  55. }  
  56. }  
  57. public boolean isFinished(){  
  58. return finished;  
  59. }  
  60. public int getDownloadSize() {  
  61. return downloadSize;  
  62. }  
  63. }  
  64. public class FileDownloadThread extends Thread{ 
  65. private static final int BUFFER_SIZE=1024; 
  66. private URL url; 
  67. private File file; 
  68. private int startPosition; 
  69. private int endPosition; 
  70. private int curPosition;//标识当前线程是否下载完成 
  71. private boolean finished=false
  72. private int downloadSize=0; 
  73. public FileDownloadThread(URL url,File file,int startPosition,int endPosition){ 
  74. this.url=url; 
  75. this.file=file; 
  76. this.startPosition=startPosition; 
  77. this.curPosition=startPosition; 
  78. this.endPosition=endPosition; 
  79. @Overridepublic void run() { 
  80. BufferedInputStream bis = null
  81. RandomAccessFile fos = null
  82. byte[] buf = new byte[BUFFER_SIZE]; 
  83. URLConnection con = null
  84. try { 
  85. con = url.openConnection(); 
  86. con.setAllowUserInteraction(true); 
  87. //设置当前线程下载的起止点 
  88. con.setRequestProperty("Range""bytes=" + startPosition + "-" + endPosition); 
  89. Log.i("bb", Thread.currentThread().getName()+" bytes=" + startPosition + "-" + endPosition); 
  90. //使用java中的RandomAccessFile 对文件进行随机读写操作 
  91. fos = new RandomAccessFile(file, "rw"); 
  92. //设置写文件的起始位置 
  93. fos.seek(startPosition); 
  94. bis = new BufferedInputStream(con.getInputStream()); 
  95. //开始循环以流的形式读写文件 
  96. while (curPosition < endPosition) { 
  97. int len = bis.read(buf, 0, BUFFER_SIZE); 
  98. if (len == -1) { 
  99. break
  100. fos.write(buf, 0, len); 
  101. curPosition = curPosition + len; 
  102. if (curPosition > endPosition) { 
  103. downloadSize+=len - (curPosition - endPosition) + 1; 
  104. else { 
  105. downloadSize+=len; 
  106. //下载完成设为true 
  107. this.finished = true
  108. bis.close(); 
  109. fos.close(); 
  110. catch (IOException e) { 
  111. e.printStackTrace(); 
  112. public boolean isFinished(){return finished;} 
  113. public int getDownloadSize() {return downloadSize;} 

这里通过RandomAccessFile 的seek方法定位到相应的位置 并实时记录下载量

当然这里需要联网和访问SD卡 所以要加上相应的权限

 

  
  1. <uses-permission android:name="android.permission.INTERNET" />  
  2. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission>  
  3. <uses-permission android:name="android.permission.INTERNET" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> 

这样就OK了 下面可以看看断点续传的问题了。有待测试~~

希望本文所述对大家的Android程序设计有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表