android多线程断点续传下载文件

时间:2021-04-10 15:25:58

一、目标

1.多线程抢占服务器资源下载。

2.断点续传。

二、实现思路。

假设分为三个线程:

1.各个线程分别向服务器请求文件的不同部分。 这个涉及Http协议,可以在Header中使用Range参数设置向服务器请求文件的范围。

2.文件部分的合并。

2.1RandomAccessFile(随机读写文件类)。

2.2分别写三个文件,最后合并。

三、编码实现

这里使用RandomAcessFile来实现,首先实现了多线程下载。


public class MainActivity extends AppCompatActivity
implements View.OnClickListener {
int i = 0;
private int progress = 0;
android.os.Handler mHandler; @Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
final ProgressBar bar = (ProgressBar) findViewById(R.id.progressBar);
Button downBtn = (Button) findViewById(R.id.button);
final EditText tcEt= (EditText) findViewById(R.id.editText2);
Button restartBtn= (Button) findViewById(R.id.button2);
restartBtn.setOnClickListener(this);
final EditText urlEdit = (EditText) findViewById(R.id.editText);
downBtn.setOnClickListener(new View.OnClickListener() {
@Override public void onClick(View v) {
new Thread() {
@Override public void run() {
try {
URL url = new URL(urlEdit.getText().toString());
HttpURLConnection connection
= (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setConnectTimeout(5000);
int length = connection.getContentLength();
Log.i("xiahong","size:"+length);
if (length < 0) {
return;
}
bar.setMax(length);
File file = new File(
Environment.getExternalStorageDirectory()
.toString(), "donw.fiel");
RandomAccessFile randomAccessFile
= new RandomAccessFile(file, "rw");
randomAccessFile.setLength(length);
int conut=Integer.valueOf(tcEt.getText().toString());
int blockSize = length / conut;
for (int i = 0; i < conut; i++) {
int begin = i * blockSize;
int end = (i + 1) * blockSize;
if (i == conut-1) {
end = length;
}
//Create Thread to Download File
Runnable runnable= new DownloadRunable(begin,
end,file,
url,i) ; new Thread(runnable).start();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}.start();
}
});
mHandler=new android.os.Handler(){
@Override public void handleMessage(Message msg) {
bar.setProgress(progress);
}
};
} @Override public void onClick(View v) {
Intent intent=getBaseContext().getPackageManager()
.getLaunchIntentForPackage(getBaseContext().getPackageName());;
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent); }   //文件下载类
class DownloadRunable implements Runnable {
private int begin;
private int end;
private File mFile;
private URL mURL;
private int id; public DownloadRunable(int begin, int end, File mFile, URL mURL, int id) {
this.begin = begin;
this.end = end;
this.mFile = mFile;
this.mURL = mURL;
this.id = id;
} @Override public void run() {
try {
HttpURLConnection connection
= (HttpURLConnection) mURL.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(5000);
connection.setRequestProperty("Range",
"bytes=" + begin + "-" + end);//向服务器请求文件范围。 InputStream is = connection.getInputStream();
byte[] bs = new byte[1024 * 1024];
RandomAccessFile randomAccessFile =
new RandomAccessFile(mFile, "rw");
randomAccessFile.seek(begin); int length = 0;
while ((length = is.read(bs)) != -1) {
randomAccessFile.write(bs, 0, length);
updateProgress(length);
}
is.close();
randomAccessFile.close();
} catch (IOException e) {
e.printStackTrace();
}
} synchronized void updateProgress(int len) {
progress += len;
mHandler.sendEmptyMessage(0);
}
}
}
下面实现断点续传。
实现思路就是将线程中耗时的循环操作加上一个Boolean类型的Flag标志,每次下载时将下载的进度保存到一个队列中,
在需要回复的时候重新创建线程,读取已保存的列表进行下载,即可。