Android 多线程断点续传下载

上下观古今,起伏千万途。这篇文章主要讲述Android 多线程断点续传下载相关的知识,希望能为你提供帮助。
通过HttpURLConnection的setRequestProperty和RandomAccessFile结合使用实现文件多线程下载和断点续传。
【Android 多线程断点续传下载】xml布局:

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

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

    推荐阅读