Android 多线程断点续传下载
Posted changchou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 多线程断点续传下载的主要内容,如果未能解决你的问题,请参考以下文章