概述:
单线程下载很简单,就是开启一个线程去下载资源再进行本地保存;
多线程下载是通过RandomAccessFile(随机文件读写操作类)来设置每个线程读取文件的起始点位置,起始点之间的长度即为该线程需要下载的文件大小
下载开始位置:线程id*每条线程下载的数据长度 = ?
下载结束位置:(线程id+1)*每条线程下载的数据长度-1=?
这里用的是URLConnection
单线程下载与多线程下载
public class DownloadActivity extends Activity implements View.OnClickListener {
private Button mButtonSingle;
private Button mButtonMuti;
private SeekBar mSeekBarDownload;
private int fileLength;
//handler用于接收多线程下载线程的消息Message,并得到文件下载进度写入进度条SeekBar
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch (msg.what){
case 0x23:
mSeekBarDownload.setProgress(msg.arg1*100/fileLength);
break;
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_download);
mSeekBarDownload = (SeekBar) findViewById(R.id.seekBar_download);
mButtonSingle = (Button) findViewById(R.id.button_download_single);
mButtonMuti = (Button) findViewById(R.id.button_download_muti);
mButtonSingle.setOnClickListener(this);
mButtonMuti.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.button_download_single:
new SingleDownloadTask().execute();
break;
case R.id.button_download_muti:
new Thread(new Runnable() {
@Override
public void run() {
downloadMuti();
}
}).start();
break;
default:
break;
}
}
/**
* 多线程下载方式
* 作用是打开网络连接,建立被下载文件存放路径,开启多个下载线程并发送文件下载进度的消息
*/
private void downloadMuti() {
try {
String urlPath = "http://192.168.0.30:8080/MyWebTest/music/aa.mp3";
URL url = new URL(urlPath);
//连接下载地址
URLConnection connection = url.openConnection();
//得到文件长度
fileLength = connection.getContentLength();
//找到或创建下载文件的存放路径
File file = new File(Environment.getExternalStorageDirectory(),"ee.mp3");
if(!file.exists()){
file.createNewFile();
}
MutiThread[] threads = new MutiThread[5];
//进行五次分段下载,因为int型的整除会舍弃余数,最后一个进程下载的长度是从文件长度的4/5到文件总长度
for(int i=0;i<5;i++){
MutiThread thread = null;
if(i==4){
thread = new MutiThread(fileLength/5*4,fileLength,urlPath,file.getAbsolutePath());
}else{
thread = new MutiThread(fileLength/5*i,fileLength/5*(i+1)-1,urlPath,file.getAbsolutePath());
}
thread.start();
threads[i] = thread;
}
boolean isFinish = true;
//如果没有下载完全时不断的更新下载进度,数据通过Message传递给handler
while (isFinish){
int sum=0;
for(MutiThread thread:threads){
sum+=thread.getSum();
}
Message msg = handler.obtainMessage();
msg.what = 0x23;
msg.arg1 = sum;
handler.sendMessage(msg);
//一般一个被下载的文件可能无法下载完全
if(sum+10>fileLength){
isFinish=false;
}
//被隔一秒,更新一次进度
Thread.sleep(1000);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//单线程下载,用的是AsyncTask线程
class SingleDownloadTask extends AsyncTask<String,Integer,String>{
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
mSeekBarDownload.setProgress((int) (values[0]*100.0/values[1]));
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
}
@Override
protected String doInBackground(String... params) {
try {
URL url = new URL("http://192.168.0.30:8080/MyWebTest/music/aa.mp3");
URLConnection connection = url.openConnection();
int length = connection.getContentLength();
InputStream is = connection.getInputStream();
File file = new File(Environment.getExternalStorageDirectory(),"aa.mp3");
if(!file.exists()){
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
byte[] array = new byte[1024];
int index = is.read(array);
int progress = 0;
while(index!=-1){
fos.write(array,0,index);
progress+=index;
publishProgress(progress,length);
index = is.read(array);
}
fos.flush();
fos.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
}
多线程的下载线程的写法
public class MutiThread extends Thread {
private int sum = 0;
private long start;
private long end;
private String urlPath;
private String filePath;
public MutiThread(long start, long end, String urlPath, String filePath) {
this.start = start;
this.end = end;
this.urlPath = urlPath;
this.filePath = filePath;
}
public int getSum() {
return sum;
}
@Override
public void run() {
try {
URL url = new URL(urlPath);
URLConnection connection = url.openConnection();
connection.setAllowUserInteraction(true);
//设置当前线程下载的起点,终点
connection.setRequestProperty("Range", "bytes=" + start + "-" + end);
InputStream is = connection.getInputStream();
byte[] array = new byte[1024];
File file = new File(filePath);
//使用java中的RandomAccessFile 对文件进行随机读写操作
RandomAccessFile randomAccessFile = new RandomAccessFile(file,"rw");
//设置开始写文件的位置
randomAccessFile.seek(start);
int index = is.read(array);
//开始循环以流的形式读写文件
while(index!=-1){
randomAccessFile.write(array,0,index);
sum += index;
index = is.read(array);
}
randomAccessFile.close();
is.close();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
结果演示:
单线程下载:
多线程下载:
显然,多线程下载要比单线程下载快得多,但前提是手机是多核的。