Andrid 多线程下载

时间:2022-11-10 20:39:48

本文转自:http://www.2cto.com/kf/201205/130969.html

本文将介绍在android平台下如何实现多线程下载,大家都知道,android平台使用java做为开发语言,所以java中支持的多线程下载方式在android平台下都支持,其中主要有两种方式可以实现多线程下载。
一种方式是使用很多个线程分别下载文件的不同部分,最后把所有下载完的文件合并成一个文件。另一种方式是使用java为我们提供的RandomAccessFile类实现多线程的下载。
从性能上分析,第二种方式的存取速度会慢一些,但开发起来较为容易,不需要进行合并文件等操作。本文将使用第二种方式来实现多线程下载,最终效果如下图所示:
 
 Andrid 多线程下载
 
 
第一步,我们先写一个线程类,来完成对指定区域的数据进行下载,如下所示:
 
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.2cto.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.2cto.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[i] = 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[i].getDownloadSize();  
141.                         if (!fds[i].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.     }