33、多线程断点下载的实现&界面的更新
1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3 android:layout_width="fill_parent"
4 android:layout_height="fill_parent"
5 android:orientation="vertical" >
6
7 <TextView
8 android:layout_width="fill_parent"
9 android:layout_height="wrap_content"
10 android:text="@string/down_load" />
11
12 <EditText
13 android:id="@+id/et"
14 android:layout_width="fill_parent"
15 android:layout_height="wrap_content"
16 android:hint="@string/hint"
17 android:text="http://192.168.1.247:8080/youdao.exe" />
18
19 <ProgressBar
20 android:id="@+id/pb"
21 style="?android:attr/progressBarStyleHorizontal"
22 android:layout_width="fill_parent"
23 android:layout_height="wrap_content" />
24
25 <TextView
26 android:id="@+id/tv_process"
27 android:layout_width="fill_parent"
28 android:layout_height="wrap_content" />
29
30 <Button
31 android:id="@+id/bt"
32 android:layout_width="fill_parent"
33 android:layout_height="wrap_content"
34 android:text="@string/download" />
35
36 </LinearLayout>
1 /**
2 * 49_多线程断点下载的实现&界面的更新 DEMO
3 * @author dr
4 *
5 */
6 public class DemoActivity extends Activity implements OnClickListener {
7
8 private ProgressBar pb;
9 private Button bt;
10 private TextView tv;
11 private EditText et;
12 boolean flag = true;
13 boolean stopflag = false;
14 int total = 0;
15
16 private Handler handler = new Handler() {
17
18 @Override
19 public void handleMessage(Message msg) {
20 pb.setProgress(total);
21 // 文件总长度
22 int max = pb.getMax();
23 // total和max都是从0开始的。
24 if (total >= (max - 1)) {
25 total = max;
26 flag = false;
27 }
28 int result = total * 100 / max;
29 tv.setText("当前进度 :" + result + "%");
30
31 super.handleMessage(msg);
32 }
33 };
34
35 @Override
36 public void onCreate(Bundle savedInstanceState) {
37 super.onCreate(savedInstanceState);
38 setContentView(R.layout.main);
39 pb = (ProgressBar) this.findViewById(R.id.pb);
40 bt = (Button) this.findViewById(R.id.bt);
41 tv = (TextView) this.findViewById(R.id.tv_process);
42 et = (EditText) this.findViewById(R.id.et);
43 bt.setOnClickListener(this);
44
45 }
46
47 @Override
48 public void onClick(View v) {
49 switch (v.getId()) {
50 case R.id.bt:
51 // 创建一个子线程 定期的更新ui
52 if ("开始下载".equals(bt.getText().toString())) {
53 bt.setText("暂停");
54 stopflag = false; // 开始下载
55 } else {
56 bt.setText("开始下载");
57 stopflag = true;
58 }
59 new Thread() {
60 @Override
61 public void run() {
62 super.run();
63 while (flag) {
64 try {
65 sleep(1000);
66 // 如果total > = 文件长度
67 Message msg = new Message();
68 handler.sendMessage(msg);
69 } catch (InterruptedException e) {
70 e.printStackTrace();
71 }
72 }
73 }
74 }.start();
75
76 // 开始执行下载的操作
77 String path = et.getText().toString().trim();
78 if ("".equals(path)) {
79 Toast.makeText(this, "路径不能为空", 1).show();
80 return;
81 }
82 try {
83 URL url = new URL(path);
84 HttpURLConnection conn = (HttpURLConnection) url
85 .openConnection();
86 conn.setRequestMethod("GET");
87 conn.setConnectTimeout(5000);
88 conn.setRequestProperty("User-Agent",
89 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
90 int code = conn.getResponseCode();
91 if (code == 200) {
92 int len = conn.getContentLength();
93 RandomAccessFile file = new RandomAccessFile("/mnt/sdcard/"
94 + getFilenName(path), "rwd");
95 // 1.设置本地文件大小跟服务器的文件大小一致
96 file.setLength(len);
97 // 设置进度条的最大值
98 pb.setMax(len);
99
100 // 2 .假设开启3 个线程
101 int threadnumber = 3;
102 int blocksize = len / threadnumber;
103 /**
104 * 线程1 0~ blocksize 线程2 1*bolocksize ~ 2*blocksize 线程3
105 * 2*blocksize ~ 文件末尾
106 */
107 for (int i = 0; i < threadnumber; i++) {
108 int startposition = i * blocksize;
109 int endpositon = (i + 1) * blocksize;
110 if (i == (threadnumber - 1)) {
111 // 最后一个线程
112 endpositon = len;
113 }
114
115 DownLoadTask task = new DownLoadTask(i, path,
116 startposition, endpositon);
117 task.start();
118 }
119
120 }
121 } catch (Exception e) {
122 Toast.makeText(this, "下载出现异常", 0).show();
123 e.printStackTrace();
124 }
125
126 break;
127 }
128
129 }
130
131 class DownLoadTask extends Thread {
132
133 int threadid;
134 String filepath;
135 int startposition;
136 int endpositon;
137
138 public DownLoadTask(int threadid, String filepath, int startposition,
139 int endpositon) {
140 this.threadid = threadid;
141 this.filepath = filepath;
142 this.startposition = startposition;
143 this.endpositon = endpositon;
144
145 }
146
147 @Override
148 public void run() {
149 try {
150 File postionfile = new File("/mnt/sdcard/" + threadid + ".txt");
151 URL url = new URL(filepath);
152 HttpURLConnection conn = (HttpURLConnection) url
153 .openConnection();
154 System.out.println("线程" + threadid + "正在下载 " + "开始位置 : "
155 + startposition + "结束位置 " + endpositon);
156
157 if (postionfile.exists()) {
158 FileInputStream fis = new FileInputStream(postionfile);
159 byte[] result = StreamTool.getBytes(fis);
160 String str = new String(result);
161 if (!"".equals(str)) {
162 int newstartposition = Integer.parseInt(str);
163 if (newstartposition > startposition) {
164 startposition = newstartposition;
165 }
166 }
167 }
168
169 // "Range", "bytes=2097152-4194303")
170 conn.setRequestProperty("Range", "bytes=" + startposition + "-"
171 + endpositon);
172 conn.setRequestMethod("GET");
173 conn.setConnectTimeout(5000);
174 conn.setRequestProperty("User-Agent",
175 "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)");
176 InputStream is = conn.getInputStream();
177 RandomAccessFile file = new RandomAccessFile("/mnt/sdcard/"
178 + getFilenName(filepath), "rwd");
179 // 设置 数据从文件哪个位置开始写
180 file.seek(startposition);
181 byte[] buffer = new byte[1024];
182 int len = 0;
183 // 代表当前读到的服务器数据的位置 ,同时这个值已经存储的文件的位置
184 int currentPostion = startposition;
185 // 创建一个文件对象 ,记录当前某个文件的下载位置
186
187 while ((len = is.read(buffer)) != -1) {
188 if (stopflag) { // 暂停下载
189 return;
190 }
191 file.write(buffer, 0, len);
192
193 synchronized (DemoActivity.this) { // 同步当前的
194 total += len;
195 }
196
197 currentPostion += len;
198 // 需要把currentPostion 信息给持久化到存储设备
199 String position = currentPostion + "";
200 FileOutputStream fos = new FileOutputStream(postionfile);
201 fos.write(position.getBytes());
202 fos.flush();
203 fos.close();
204 }
205
206 file.close();
207 System.out.println("线程" + threadid + "下载完毕");
208 // 当线程下载完毕后 把文件删除掉
209 if (postionfile.exists()) {
210 postionfile.delete();
211 }
212 } catch (Exception e) {
213 e.printStackTrace();
214 }
215 super.run();
216 }
217 }
218
219 public String getFilenName(String path) {
220 int start = path.lastIndexOf("/") + 1;
221 return path.substring(start, path.length());
222 }
223 }
1 public class StreamTool {
2 /**
3 * 把一个inputstream里面的内容转化成一个byte[]
4 */
5 public static byte[] getBytes(InputStream is) throws Exception{
6 ByteArrayOutputStream bos = new ByteArrayOutputStream();
7 byte[] buffer = new byte[1024];
8 int len = 0;
9 while((len = is.read(buffer))!=-1){
10 bos.write(buffer, 0, len);
11 }
12 is.close();
13 bos.flush();
14 byte[] result = bos.toByteArray();
15 System.out.println(new String(result));
16 return result;
17 }
18 }
1 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
2 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
3 <uses-permission android:name="android.permission.INTERNET"/>