android多线程断点下载,带进度条和百分比显示,断点下载的临时数据保存到SD卡的文本文档中,建议可以保存到本地数据库中,这样可以提高存取效率,从而提高系统性能。
效果:
打开软件:
下载中:
下载完毕:
附代码如下:
1 package com.yy.multiDownloadOfBreakPoint;
2
3 import java.io.File;
4 import java.io.FileInputStream;
5 import java.io.InputStream;
6 import java.io.RandomAccessFile;
7 import java.net.HttpURLConnection;
8 import java.net.URL;
9
10 import android.app.Activity;
11 import android.os.Bundle;
12 import android.os.Handler;
13 import android.os.Message;
14 import android.text.TextUtils;
15 import android.view.View;
16 import android.widget.EditText;
17 import android.widget.ProgressBar;
18 import android.widget.TextView;
19 import android.widget.Toast;
20 /**
21 * 多线程断点下载实例
22 * @author YUANYUAN
23 *
24 */
25 public class MainActivity extends Activity {
26 //下载所使用的线程数
27 protected static final int threadCount = 3;
28 //下载完毕的标记
29 public static final int downloadOver = 1;
30 //更新下载进度标记
31 public static final int UPDATE_PROGRESS = 0;
32 //下载资源的路径输入框
33 private EditText et_path;
34 //下载的进度条
35 private ProgressBar pb;
36 //进度显示
37 private TextView tv_pb;
38 //当前累计下载的数据
39 int curDownCount=0;
40 //当前活动的下载线程数
41 protected static int activeThread;
42 //加入消息处理机制
43 private Handler handler=new Handler(){
44 @Override
45 public void handleMessage(Message msg) {
46 switch (msg.what) {
47 case downloadOver:
48 Toast.makeText(MainActivity.this, "文件已下载完毕!", Toast.LENGTH_LONG).show();
49 tv_pb.setText("下载完成");
50 break;
51 case UPDATE_PROGRESS:
52 //更新进度显示
53 tv_pb.setText("当前进度:"+(pb.getProgress()*100/pb.getMax())+"%");
54 break;
55 default:
56 break;
57 }
58 }
59 };
60
61 @Override
62 protected void onCreate(Bundle savedInstanceState) {
63 super.onCreate(savedInstanceState);
64 setContentView(R.layout.activity_main);
65 et_path=(EditText) findViewById(R.id.et_path);
66 et_path.setText("http://192.168.2.114:8080/sqlite.exe");
67 pb=(ProgressBar) findViewById(R.id.pb);
68 tv_pb=(TextView) findViewById(R.id.tv_pb);
69 }
70
71 /**
72 * 开始下载
73 * @param view
74 */
75 public void down(View view){
76 //获取下载资源的路径
77 final String path=et_path.getText().toString().trim();
78 //判断资源路径是否为空
79 if (TextUtils.isEmpty(path)) {
80 Toast.makeText(this, "请输入下载资源的路径", Toast.LENGTH_LONG).show();
81 return;
82 }
83 //开启一个线程进行下载
84 new Thread(){
85 public void run() {
86 try {
87 //构造URL地址
88 URL url=new URL(path);
89 //打开连接
90 HttpURLConnection conn=(HttpURLConnection) url.openConnection();
91 //设置请求超时的时间
92 conn.setConnectTimeout(5000);
93 //设置请求方式
94 conn.setRequestMethod("GET");
95 //获取相应码
96 int code=conn.getResponseCode();
97 if (code==200) {//请求成功
98 //获取请求数据的长度
99 int length=conn.getContentLength();
100 //设置进度条的最大值
101 pb.setMax(length);
102 //在客户端创建一个跟服务器文件大小相同的临时文件
103 RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd");
104 //指定临时文件的长度
105 raf.setLength(length);
106 raf.close();
107 //假设3个线程去下载资源
108 //平均每一个线程要下载的文件的大小
109 int blockSize=length/threadCount;
110 for (int threadId = 1; threadId <= threadCount; threadId++) {
111 //当前线程下载数据的开始位置
112 int startIndex=blockSize*(threadId-1);
113 //当前线程下载数据的结束位置
114 int endIndex=blockSize*threadId-1;
115 //确定最后一个线程要下载数据的最大位置
116 if (threadId==threadCount) {
117 endIndex=length;
118 }
119 //显示下载数据的区间
120 System.out.println("线程【"+threadId+"】开始下载:"+startIndex+"---->"+endIndex);
121 //开启下载的子线程
122 new DownloadThread(path, threadId, startIndex, endIndex).start();
123 //当前下载活动的线程数加1
124 activeThread++;
125 System.out.println("当前活动的线程数:"+activeThread);
126 }
127
128 }else{//请求失败
129 System.out.println("服务器异常,下载失败!");
130 }
131 } catch (Exception e) {
132 e.printStackTrace();
133 System.out.println("服务器异常,下载失败!");
134 }
135 };
136 }.start();
137
138 }
139 /**
140 * 下载文件的子线程 每一个文件都下载对应的数据
141 * @author YUANYUAN
142 *
143 */
144 public class DownloadThread extends Thread{
145 private String path;
146 private int threadId;
147 private int startIndex;
148 private int endIndex;
149
150 /**
151 * 构造方法
152 * @param path 下载文件的路径
153 * @param threadId 下载文件的线程
154 * @param startIndex 下载文件开始的位置
155 * @param endIndex 下载文件结束的位置
156 */
157 public DownloadThread(String path, int threadId, int startIndex,
158 int endIndex) {
159 this.path = path;
160 this.threadId = threadId;
161 this.startIndex = startIndex;
162 this.endIndex = endIndex;
163 }
164
165
166
167 @Override
168 public void run() {
169 //构造URL地址
170 try {
171
172 File tempFile=new File("sdcard/"+threadId+".txt");
173 //检查记录是否存在,如果存在读取数据,设置真实下载开始的位置
174 if (tempFile.exists()) {
175 FileInputStream fis=new FileInputStream(tempFile);
176 byte[] temp=new byte[1024];
177 int length=fis.read(temp);
178 //读取到已经下载的位置
179 int downloadNewIndex=Integer.parseInt(new String(temp, 0, length));
180 //计算出已经下载的数据长度
181 int areadyDown=downloadNewIndex-startIndex;
182 //累加已经下载的数据量
183 curDownCount+=areadyDown;
184 //设置进度条已经下载的数据量
185 pb.setProgress(curDownCount);
186 //设置重新开始下载的开始位置
187 startIndex=downloadNewIndex;
188 fis.close();
189 //显示真实下载数据的区间
190 System.out.println("线程【"+threadId+"】真实开始下载数据区间:"+startIndex+"---->"+endIndex);
191 }
192
193 URL url = new URL(path);
194 HttpURLConnection conn=(HttpURLConnection) url.openConnection();
195 conn.setConnectTimeout(5000);
196 conn.setRequestMethod("GET");
197 //设置请求属性,请求部分资源
198 conn.setRequestProperty("Range", "bytes="+startIndex+"-"+endIndex);
199 int code=conn.getResponseCode();
200 if (code==206) {//下载部分资源,正常返回的状态码为206
201 InputStream is=conn.getInputStream();//已经设置了请求的位置,所以返回的是对应的部分资源
202 //构建随机访问文件
203 RandomAccessFile raf=new RandomAccessFile("sdcard/setup.exe", "rwd");
204 //设置 每一个线程随机写文件开始的位置
205 raf.seek(startIndex);
206 //开始写文件
207 int len=0;
208 byte[] buffer=new byte[1024];
209 //该线程已经下载数据的长度
210 int total=0;
211
212 while((len=is.read(buffer))!=-1){//读取输入流
213 //记录当前线程已下载数据的长度
214 RandomAccessFile file=new RandomAccessFile("sdcard/"+threadId+".txt","rwd");
215 raf.write(buffer,0,len);//写文件
216 total+=len;//更新该线程已下载数据的总长度
217 System.out.println("线程【"+threadId+"】已下载数据:"+(total+startIndex));
218 //将已下载数据的位置记录写入到文件
219 file.write((startIndex+total+"").getBytes());
220 //累加已经下载的数据量
221 curDownCount+=len;
222 //更新进度条【进度条的更新可以在非UI线程直接更新,具体见底层源代码】
223 pb.setProgress(curDownCount);
224
225 //更新下载进度
226 Message msg=Message.obtain();
227 msg.what=UPDATE_PROGRESS;
228 handler.sendMessage(msg);
229
230 file.close();
231 }
232 is.close();
233 raf.close();
234 //提示下载完毕
235 System.out.println("线程【"+threadId+"】下载完毕");
236 }
237 } catch (Exception e) {
238 e.printStackTrace();
239 System.out.println("线程【"+threadId+"】下载出现异常!!");
240 }finally{
241 //活动的线程数减少
242 activeThread--;
243 if (activeThread==0) {
244 for (int i = 1; i <= threadCount; i++) {
245 File tempFile=new File("sdcard/"+i+".txt");
246 tempFile.delete();
247 }
248 System.out.println("下载完毕,已清除全部临时文件");
249 //界面消息提示下载完毕
250 Message msg=new Message();
251 msg.what=downloadOver;
252 handler.sendMessage(msg);
253 }
254 }
255
256 }
257 }
258 }