首页 > 代码库 > Android 多线程断点续传下载

Android 多线程断点续传下载

通过HttpURLConnection的setRequestProperty和RandomAccessFile结合使用实现文件多线程下载和断点续传。

xml布局:

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:tools="http://schemas.android.com/tools"
 4     android:id="@+id/activity_main"
 5     android:layout_width="match_parent"
 6     android:layout_height="match_parent"
 7     android:orientation="vertical"
 8     android:paddingBottom="@dimen/activity_vertical_margin"
 9     android:paddingLeft="@dimen/activity_horizontal_margin"
10     android:paddingRight="@dimen/activity_horizontal_margin"
11     android:paddingTop="@dimen/activity_vertical_margin"
12     tools:context="com.zhang.multidown.MainActivity">
13 
14     <EditText
15         android:id="@+id/et_fileUrl"
16         android:layout_width="match_parent"
17         android:layout_height="wrap_content"
18         android:inputType="textUri" />
19 
20     <ProgressBar
21         android:id="@+id/progressBar"
22         style="@style/Widget.AppCompat.ProgressBar.Horizontal"
23         android:layout_width="match_parent"
24         android:layout_height="wrap_content" />
25 
26     <Button
27         android:id="@+id/btn_down"
28         android:layout_width="match_parent"
29         android:layout_height="wrap_content"
30         android:onClick="onClickDown"
31         android:text="下载" />
32 </LinearLayout>
  1 package com.zhang.multidown;
  2 
  3 import android.os.Bundle;
  4 import android.os.Environment;
  5 import android.support.v7.app.AppCompatActivity;
  6 import android.view.View;
  7 import android.widget.Button;
  8 import android.widget.EditText;
  9 import android.widget.ProgressBar;
 10 import android.widget.Toast;
 11 
 12 import java.io.File;
 13 import java.io.IOException;
 14 import java.io.InputStream;
 15 import java.io.RandomAccessFile;
 16 import java.net.HttpURLConnection;
 17 import java.net.MalformedURLException;
 18 import java.net.URL;
 19 import java.util.ArrayList;
 20 import java.util.HashMap;
 21 import java.util.List;
 22 
 23 public class MainActivity extends AppCompatActivity {
 24 
 25     private ProgressBar progressBar;
 26     private EditText etUrl;
 27     private Button btnDown;
 28     private int total = 0;
 29     private boolean downloading = false;
 30     private URL url;
 31     private File file;
 32     private List<HashMap<String, Integer>> threadList;
 33     private int length;
 34 
 35 //    Handler handler = new Handler(new Handler.Callback() {
 36 //        @Override
 37 //        public boolean handleMessage(Message msg) {
 38 //            if (msg.what == 0) {
 39 //                progressBar.setProgress(msg.arg1);
 40 //                if (msg.arg1 == length) {
 41 //                    Toast.makeText(MainActivity.this, "下载完成!", Toast.LENGTH_SHORT).show();
 42 //                    total = 0;
 43 //                }
 44 //            }
 45 //            return false;
 46 //        }
 47 //    });
 48 
 49     @Override
 50     protected void onCreate(Bundle savedInstanceState) {
 51         super.onCreate(savedInstanceState);
 52         setContentView(R.layout.activity_main);
 53 
 54         progressBar = (ProgressBar) findViewById(R.id.progressBar);
 55         etUrl = (EditText) findViewById(R.id.et_fileUrl);
 56         btnDown = (Button) findViewById(R.id.btn_down);
 57         threadList = new ArrayList<>();
 58 
 59     }
 60 
 61     public void onClickDown(View view) {
 62 
 63         if (downloading) {
 64             downloading = false;
 65             btnDown.setText("下载");
 66             return;
 67         }
 68         downloading = true;
 69         btnDown.setText("暂停");
 70 
 71         if (threadList.size() == 0) {
 72             new Thread(new Runnable() {
 73                 @Override
 74                 public void run() {
 75                     try {
 76                         url = new URL(etUrl.getText().toString());
 77                         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
 78                         connection.setRequestMethod("GET");
 79                         connection.setConnectTimeout(5000);
 80                         connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)");
 81                         length = connection.getContentLength();
 82                         progressBar.setMax(length);
 83                         progressBar.setProgress(0);
 84 
 85                         if (length < 0) {
 86                             runOnUiThread(new Runnable() {
 87                                 @Override
 88                                 public void run() {
 89                                     Toast.makeText(MainActivity.this, "File not found !", Toast.LENGTH_SHORT).show();
 90                                 }
 91                             });
 92 
 93                             return;
 94                         }
 95 
 96                         file = new File(Environment.getExternalStorageDirectory(), getFileName(etUrl.getText().toString()));
 97                         RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
 98                         randomAccessFile.setLength(length);
 99 
100                         int blockSize = length / 3;
101                         for (int i = 0; i < 3; i++) {
102                             int begin = i * blockSize;
103                             int end = (i + 1) * blockSize - 1;
104                             if (i == 2) {
105                                 end = length;
106                             }
107 
108                             HashMap<String, Integer> map = new HashMap<>();
109                             map.put("begin", begin);
110                             map.put("end", end);
111                             map.put("finished", 0);
112                             threadList.add(map);
113 
114                             //创建线程 下载文件
115                             new Thread(new DownloadRunnable(begin, end, i, file, url)).start();
116                         }
117 
118                     } catch (MalformedURLException e) {
119                         e.printStackTrace();
120                         Toast.makeText(MainActivity.this, "URL Error !", Toast.LENGTH_SHORT).show();
121                     } catch (IOException e) {
122                         e.printStackTrace();
123                     }
124                 }
125             }).start();
126         } else {
127             //恢复下载
128             for (int i = 0; i < threadList.size(); i++) {
129                 HashMap<String, Integer> map = threadList.get(i);
130                 int begin = map.get("begin");
131                 int end = map.get("end");
132                 int finished = map.get("finished");
133                 new Thread(new DownloadRunnable(begin + finished, end, i, file, url)).start();
134             }
135         }
136     }
137 
138     private String getFileName(String url) {
139         int index = url.lastIndexOf("/") + 1;
140         return url.substring(index);
141     }
142 
143     class DownloadRunnable implements Runnable {
144 
145         private int begin;
146         private int end;
147         private int id;
148         private File file;
149         private URL url;
150 
151         public DownloadRunnable(int begin, int end, int id, File file, URL url) {
152             this.begin = begin;
153             this.end = end;
154             this.id = id;
155             this.file = file;
156             this.url = url;
157         }
158 
159         @Override
160         public void run() {
161             try {
162                 if (begin > end) {
163                     return;
164                 }
165                 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
166                 connection.setRequestMethod("GET");
167                 connection.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; .NET CLR 2.0.50727)");
168                 connection.setRequestProperty("Range", "bytes=" + begin + "-" + end);
169 
170                 InputStream is = connection.getInputStream();
171                 byte[] buf = new byte[1024 * 1024];
172                 RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw");
173                 randomAccessFile.seek(begin);
174                 int len;
175                 HashMap<String, Integer> map = threadList.get(id);
176                 while ((len = is.read(buf)) != -1 && downloading) {
177                     randomAccessFile.write(buf, 0, len);
178                     updateProgress(len);
179                     map.put("finished", map.get("finished") + len);
180                     System.out.println("Download:" + total);
181                 }
182                 is.close();
183                 randomAccessFile.close();
184 
185             } catch (IOException e) {
186                 e.printStackTrace();
187             }
188         }
189     }
190 
191     synchronized private void updateProgress(int len) {
192         total += len;
193 //        handler.obtainMessage(0, total, 0).sendToTarget();
194         runOnUiThread(new Runnable() {
195             @Override
196             public void run() {
197                 progressBar.setProgress(total);
198                 if (total == length) {
199                     Toast.makeText(MainActivity.this, "下载完成!", Toast.LENGTH_SHORT).show();
200                     total = 0;
201                     btnDown.setText("完成");
202                 }
203             }
204         });
205     }
206 }

manifest需要添加网络权限和文件写入权限。

 

Android 多线程断点续传下载