Android进阶:实现多线程下载文件

网友投稿 1490 2022-12-01

Android进阶:实现多线程-文件

Android进阶:实现多线程-文件

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

首先看下效果图

创建工程 ThreadDemo

首先布局文件 threaddemo.xml

​​view plain​​​ ​​​copy to clipboard​​​ ​​​print​​​ ​​​?​​ 1. 2. 7. 12. 18. 23. 28. 34. 40. 46.

主界面 Acitivity

​​view plain​​​ ​​​copy to clipboard​​​ ​​​print​​​ ​​​?​​ 1. public class2. 3. private4. private5. private6. private7. private8. private int9. private int10. 11. private long12. 13. @Override14. public void15. super.onCreate(savedInstanceState);16. setContentView(R.layout.threaddemo);17. 18. downloadurl = (TextView) findViewById(R.id.downloadurl);19. "downloadnum = (EditText) findViewById(R.id.downloadnum);21. downloadinfo = (TextView) findViewById(R.id.downloadinfo);22. downloadbutton = (Button) findViewById(R.id.downloadbutton);23. downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);24. downloadProgressBar.setVisibility(View.VISIBLE);25. downloadProgressBar.setMax(100);26. downloadProgressBar.setProgress(0);27. new28. public void29. download();30. downloadtime = SystemClock.currentThreadTimeMillis();31. }32. });33. }34. 35. private void36. // 获取SD卡目录37. String dowloadDir = Environment.getExternalStorageDirectory()38. "/threaddemodownload/";39. new40. //创建-目录41. if42. file.mkdirs();43. }44. 45. //读取-线程数,如果为空,则单线程-46. int downloadTN = Integer.valueOf("".equals(downloadnum.getText()47. "1"48. "hetang.mp3";49. //开始-前把-按钮设置为不可用50. false);51. //进度条设为052. downloadProgressBar.setProgress(0);53. //启动文件-线程54. new downloadTask("Integer55. .valueOf(downloadTN), dowloadDir + fileName).start();56. }57. 58. new59. @Override60. public void61. //当收到更新视图消息时,计算已完成-百分比,同时更新进度条信息62. int63. if64. true);65. "-完成!");66. new AlertDialog.Builder(ThreadDownloadDemo.this)67. "提示信息")68. "-完成,总用时为:"+(SystemClock.currentThreadTimeMillis()-downloadtime)+"毫秒")69. "确定", new70. @Override71. public void onClick(DialogInterface dialog, int72. dialog.dismiss();73. }74. })75. .create();76. mdialog.show();77. else78. "当前进度:" + progress + "%");79. }80. downloadProgressBar.setProgress(progress);81. }82. 83. };84. 85. 86. public class87. private int88. private int89. String urlStr, threadNo, fileName;90. 91. public downloadTask(String urlStr, int92. this.urlStr = urlStr;93. this.threadNum = threadNum;94. this.fileName = fileName;95. }96. 97. @Override98. public void99. new100. try101. new102. URLConnection conn = url.openConnection();103. //防止返回-1104. in105. //获取-文件的总大小106. fileSize = conn.getContentLength();107. "bb", "======================fileSize:"+fileSize);108. //计算每个线程要-的数据量109. blockSize = fileSize / threadNum;110. // 解决整除后百分比计算误差111. downloadSizeMore = (fileSize % threadNum);112. new113. for (int114. "bb", "======================i:"+i);115. //启动线程,分别-自己需要-的部分116. new117. "Thread"118. fdt.start();119. fds[i] = fdt;120. }121. false;122. while123. // 先把整除的余数搞定124. downloadedSize = downloadSizeMore;125. true;126. for (int127. downloadedSize += fds[i].getDownloadSize();128. if129. false;130. }131. }132. handler.sendEmptyMessage(0);133. //线程暂停一秒134. sleep(1000);135. }136. catch137. e.printStackTrace();138. }139. 140. }141. }142. }public class ThreadDownloadDemo extends Activity { private TextView downloadurl;private EditText downloadnum;private Button downloadbutton;private ProgressBar downloadProgressBar;private TextView downloadinfo;private int downloadedSize = 0;private int fileSize = 0;private long downloadtime; @Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.threaddemo); downloadurl = (TextView) findViewById(R.id.downloadurl);downloadurl.setText("= (EditText) findViewById(R.id.downloadnum);downloadinfo = (TextView) findViewById(R.id.downloadinfo);downloadbutton = (Button) findViewById(R.id.downloadbutton);downloadProgressBar = (ProgressBar) findViewById(R.id.downloadProgressBar);downloadProgressBar.setVisibility(View.VISIBLE);downloadProgressBar.setMax(100);downloadProgressBar.setProgress(0);downloadbutton.setOnClickListener(new OnClickListener() {public void onClick(View v) {download();downloadtime = SystemClock.currentThreadTimeMillis();}});} private void download() {// 获取SD卡目录String dowloadDir = Environment.getExternalStorageDirectory()+ "/threaddemodownload/";File file = new File(dowloadDir);//创建-目录if (!file.exists()) {file.mkdirs();}//读取-线程数,如果为空,则单线程-int downloadTN = Integer.valueOf("".equals(downloadnum.getText().toString()) ? "1" : downloadnum.getText().toString());String fileName = "hetang.mp3";//开始-前把-按钮设置为不可用downloadbutton.setClickable(false);//进度条设为0downloadProgressBar.setProgress(0);//启动文件-线程new downloadTask("Integer.valueOf(downloadTN), dowloadDir + fileName).start();} Handler handler = new Handler() {@Overridepublic void handleMessage(Message msg) {//当收到更新视图消息时,计算已完成-百分比,同时更新进度条信息int progress = (Double.valueOf((downloadedSize * 1.0 / fileSize * 100))).intValue();if (progress == 100) {downloadbutton.setClickable(true);downloadinfo.setText("-完成!");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();}}).create();mdialog.show();} else {downloadinfo.setText("当前进度:" + progress + "%");}downloadProgressBar.setProgress(progress);} }; public class downloadTask extends Thread {private int blockSize, downloadSizeMore;private int threadNum = 5;String urlStr, threadNo, fileName; public downloadTask(String urlStr, int threadNum, String fileName) {this.urlStr = urlStr;this.threadNum = threadNum;this.fileName = fileName;} @Overridepublic void run() {FileDownloadThread[] fds = new FileDownloadThread[threadNum];try {URL url = new URL(urlStr);URLConnection conn = url.openConnection();//防止返回-1InputStream in = conn.getInputStream();//获取-文件的总大小fileSize = conn.getContentLength();Log.i("bb", "======================fileSize:"+fileSize);//计算每个线程要-的数据量blockSize = fileSize / threadNum;// 解决整除后百分比计算误差downloadSizeMore = (fileSize % threadNum);File file = new File(fileName);for (int i = 0; i < threadNum; i++) {Log.i("bb", "======================i:"+i);//启动线程,分别-自己需要-的部分FileDownloadThread fdt = new FileDownloadThread(url, file, i * blockSize, (i + 1) * blockSize - 1);fdt.setName("Thread" + i);fdt.start();fds[i] = fdt;}boolean finished = false;while (!finished) {// 先把整除的余数搞定downloadedSize = downloadSizeMore;finished = true;for (int i = 0; i < fds.length; i++) {downloadedSize += fds[i].getDownloadSize();if (!fds[i].isFinished()) {finished = false;}}handler.sendEmptyMessage(0);//线程暂停一秒sleep(1000);}} catch (Exception e) {e.printStackTrace();} }}}

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

-文件的线程

​​view plain​​​ ​​​copy to clipboard​​​ ​​​print​​​ ​​​?​​

1. public class2. private static final int3. private4. private5. private int6. private int7. private int8. //标识当前线程是否-完成9. private boolean finished=false;10. private int11. public FileDownloadThread(URL url,File file,int startPosition,int12. this.url=url;13. this.file=file;14. this.startPosition=startPosition;15. this.curPosition=startPosition;16. this.endPosition=endPosition;17. }18. @Override19. public void20. null;21. null;22. byte[] buf = new byte[BUFFER_SIZE];23. null;24. try25. con = url.openConnection();26. true);27. //设置当前线程-的起止点28. "Range", "bytes=" + startPosition + "-"29. "bb", Thread.currentThread().getName()+" bytes=" + startPosition + "-"30. //使用java中的RandomAccessFile 对文件进行随机读写操作31. new RandomAccessFile(file, "rw");32. //设置写文件的起始位置33. fos.seek(startPosition);34. new35. //开始循环以流的形式读写文件36. while37. int38. if39. break;40. }41. fos.write(buf, 0, len);42. curPosition = curPosition + len;43. if44. downloadSize+=len - (curPosition - endPosition) + 1;45. else46. downloadSize+=len;47. }48. }49. //-完成设为true50. this.finished = true;51. bis.close();52. fos.close();53. catch54. e.printStackTrace();55. }56. }57. 58. public59. return60. }61. 62. public int63. return64. }65. }public class FileDownloadThread extends Thread{private static final int BUFFER_SIZE=1024;private URL url;private File file;private int startPosition;private int endPosition;private int curPosition;//标识当前线程是否-完成private boolean finished=false;private int downloadSize=0;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;}@Overridepublic void run() { BufferedInputStream bis = null; RandomAccessFile fos = null; byte[] buf = new byte[BUFFER_SIZE]; URLConnection con = null; try { con = url.openConnection(); con.setAllowUserInteraction(true); //设置当前线程-的起止点 con.setRequestProperty("Range", "bytes=" + startPosition + "-" + endPosition); Log.i("bb", Thread.currentThread().getName()+" bytes=" + startPosition + "-" + endPosition); //使用java中的RandomAccessFile 对文件进行随机读写操作 fos = new RandomAccessFile(file, "rw"); //设置写文件的起始位置 fos.seek(startPosition); bis = new BufferedInputStream(con.getInputStream()); //开始循环以流的形式读写文件 while (curPosition < endPosition) { int len = bis.read(buf, 0, BUFFER_SIZE); if (len == -1) { break; } fos.write(buf, 0, len); curPosition = curPosition + len; if (curPosition > endPosition) { downloadSize+=len - (curPosition - endPosition) + 1; } else { downloadSize+=len; } } //-完成设为true this.finished = true; bis.close(); fos.close(); } catch (IOException e) { e.printStackTrace(); }} public boolean isFinished(){return finished;} public int getDownloadSize() {return downloadSize;}}

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

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

"android.permission.INTERNET" 1. "android.permission.WRITE_EXTERNAL_STORAGE">

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

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:使用Android内部的DownloadProvider下载文件,并获取cache权限
下一篇:ActionBar使用方法 - Android活动栏(二)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~