android多线程下载详解
3169 点击·0 回帖
![]() | ![]() | |
![]() | 本文将介绍在Android平台下如何实现多线程下载,大家都知道,Android平台使用java做为开发语言,所以java中支持的多线程下载方式在Android平台下都支持,其中主要有两种方式可以实现多线程下载。 一种方式是使用很多个线程分别下载文件的不同部分,最后把所有下载完的文件合并成一个文件。另一种方式是使用java为我们提供的RandomAccessFile类实现多线程的下载。 从性能上分析,第二种方式的存取速度会慢一些,但开发起来较为容易,不需要进行合并文件等操作。本文将使用第二种方式来实现多线程下载,最终效果如下图所示: ![]() 第一步,我们先写一个线程类,来完成对指定区域的数据进行下载,如下所示: java代码 1. package com.ideasAndroid.demo; 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. 10. import Android.util.Log; 11. /** 12. * Copyright (C) 2010 ideasAndroid 13. * 演示Android多线程下载 14. * 欢迎访问http://www.atcpu.com 15. * 让程序开发不再那么神秘 16. * 17. * 单个下载线程 18. */ 19. public class FileDownloadThread extends Thread{ 20. private static final int BUFFER_SIZE=1024; 21. private URL url; 22. private File file; 23. private int startPosition; 24. private int endPosition; 25. private int curPosition; 26. //用于标识当前线程是否下载完成 27. private boolean finished=false; 28. private int downloadSize=0; 29. public FileDownloadThread(URL url,File file,int startPosition,int endPosition){ 30. this.url=url; 31. this.file=file; 32. this.startPosition=startPosition; 33. this.curPosition=startPosition; 34. this.endPosition=endPosition; 35. } 36. @Override 37. public void run() { 38. BufferedInputStream bis = null; 39. RandomAccessFile fos = null; 40. byte[] buf = new byte[BUFFER_SIZE]; 41. URLConnection con = null; 42. try { 43. con = url.openConnection(); 44. con.setAllowUserinteraction(true); 45. //设置当前线程下载的起点,终点 46. con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition); 47. //使用java中的RandomAccessFile 对文件进行随机读写操作 48. fos = new RandomAccessFile(file, "rw"); 49. //设置开始写文件的位置 50. fos.seek(startPosition); 51. bis = new BufferedInputStream(con.getInputStream()); 52. //开始循环以流的形式读写文件 53. while (curPosition < endPosition) { 54. int len = bis.read(buf, 0, BUFFER_SIZE); 55. if (len == -1) { 56. break; 57. } 58. fos.write(buf, 0, len); 59. curPosition = curPosition + len; 60. if (curPosition > endPosition) { 61. downloadSize+=len - (curPosition - endPosition) + 1; 62. } else { 63. downloadSize+=len; 64. } 65. } 66. //下载完成设为true 67. this.finished = true; 68. bis.close(); 69. fos.close(); 70. } catch (IOException e) { 71. Log.d(getName() +" Error:", e.getMessage()); 72. } 73. } 74. 75. public boolean isFinished(){ 76. return finished; 77. } 78. 79. public int getDownloadSize() { 80. return downloadSize; 81. } 82. } 接下来就是使用图形界面来获取需要下载的内容,并实时更新下载进度条,代码如下所示: java代码 1. package com.ideasAndroid.demo; 2. 3. import java.io.File; 4. import java.net.URL; 5. import java.net.URLConnection; 6. import Android.app.Activity; 7. import Android.os.Bundle; 8. import Android.os.Environment; 9. import Android.os.Handler; 10. import Android.os.Message; 11. import Android.view.View; 12. import Android.view.View.OnClickListener; 13. import Android.widget.Button; 14. import Android.widget.EditText; 15. import Android.widget.ProgressBar; 16. import Android.widget.TextView; 17. /** 18. * Copyright (C) 2010 ideasAndroid 19. * 演示Android多线程下载 20. * 欢迎访问http://www.atcpu.com 21. * 让程序开发不再那么神秘 22. */ 23. public class FileDownloadDemo extends Activity { 24. 25. private EditText downloadUrl; 26. private EditText downloadFileName; 27. private EditText downloadThreadNum; 28. private Button downloadBt; 29. private ProgressBar downloadProgressBar; 30. private TextView progressMessage; 31. private int downloadedSize = 0; 32. private int fileSize = 0; 33. 34. @Override 35. public void onCreate(Bundle savedInstanceState) { 36. super.onCreate(savedInstanceState); 37. setContentView(R.layout.main); 38. 39. downloadUrl = (EditText) findViewById(R.id.downloadUrl); 40. downloadFileName = (EditText) findViewById(R.id.downloadFileName); 41. downloadThreadNum = (EditText) findViewById(R.id.downloadThreadNum); 42. progressMessage = (TextView) findViewById(R.id.progressMessage); 43. downloadBt = (Button) findViewById(R.id.downloadBt); 44. downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar); 45. downloadProgressBar.setVisibility(View.VISIBLE); 46. downloadProgressBar.setMax(100); 47. downloadProgressBar.setProgress(0); 48. downloadBt.setOnClickListener(new OnClickListener() { 49. public void onClick(View v) { 50. download(); 51. } 52. }); 53. } 54. 55. private void download() { 56. // 获取SD卡目录 57. String dowloadDir = Environment.getExternalStorageDirectory() 58. + "/ideasdownload/"; 59. File file = new File(dowloadDir); 60. //创建下载目录 61. if (!file.exists()) { 62. file.mkdirs(); 63. } 64. 65. //读取下载线程数,如果为空,则单线程下载 66. int downloadTN = Integer.valueOf("".equals(downloadThreadNum.getText() 67. .toString()) ? "1" : downloadThreadNum.getText().toString()); 68. //如果下载文件名为空则获取Url尾为文件名 69. int fileNameStart = downloadUrl.getText().toString().lastIndexOf("/"); 70. String fileName = "".equals(downloadFileName.getText().toString()) ? downloadUrl 71. .getText().toString().substring(fileNameStart) 72. : downloadFileName.getText().toString(); 73. //开始下载前把下载按钮设置为不可用 74. downloadBt.setClickable(false); 75. //进度条设为0 76. downloadProgressBar.setProgress(0); 77. //启动文件下载线程 78. new downloadTask(downloadUrl.getText().toString(), Integer 79. .valueOf(downloadTN), dowloadDir + fileName).start(); 80. } 81. 82. Handler handler = new Handler() { 83. @Override 84. public void handleMessage(Message msg) { 85. //当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息 86. int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue(); 87. if (progress == 100) { 88. downloadBt.setClickable(true); 89. progressMessage.setText("下载完成!"); 90. } else { 91. progressMessage.setText("当前进度:" + progress + "%"); 92. } 93. downloadProgressBar.setProgress(progress); 94. } 95. 96. }; 97. 98. /** 99. * @author ideasAndroid 100. * 主下载线程 101. */ 102. public class downloadTask extends Thread { 103. private int blockSize, downloadSizeMore; 104. private int threadNum = 5; 105. String urlStr, threadNo, fileName; 106. 107. public downloadTask(String urlStr, int threadNum, String fileName) { 108. this.urlStr = urlStr; 109. this.threadNum = threadNum; 110. this.fileName = fileName; 111. } 112. 113. @Override 114. public void run() { 115. FileDownloadThread[] fds = new FileDownloadThread[threadNum]; 116. try { 117. URL url = new URL(urlStr); 118. URLConnection conn = url.openConnection(); 119. //获取下载文件的总大小 120. fileSize = conn.getContentLength(); 121. //计算每个线程要下载的数据量 122. blockSize = fileSize / threadNum; 123. // 解决整除后百分比计算误差 124. downloadSizeMore = (fileSize % threadNum); 125. File file = new File(fileName); 126. for (int i = 0; i < threadNum; i++) { 127. //启动线程,分别下载自己需要下载的部分 128. FileDownloadThread fdt = new FileDownloadThread(url, file, 129. i * blockSize, (i + 1) * blockSize - 1); 130. fdt.setName("Thread" + i); 131. fdt.start(); 132. fds = fdt; 133. } 134. boolean finished = false; 135. while (!finished) { 136. // 先把整除的余数搞定 137. downloadedSize = downloadSizeMore; 138. finished = true; 139. for (int i = 0; i < fds.length; i++) { 140. downloadedSize += fds.getDownloadSize(); 141. if (!fds.isFinished()) { 142. finished = false; 143. } 144. } 145. //通知handler去更新视图组件 146. handler.sendEmptyMessage(0); 147. //休息1秒后再读取下载进度 148. sleep(1000); 149. } 150. } catch (Exception e) { 151. 152. } 153. 154. } 155. } | |
![]() | ![]() |