本文将介绍在android平台下如何实现多线程下载,大家都知道,android平台使用java做为开发语言,所以java中支持的多线程下载方式在android平台下都支持,其中主要有两种方式可以实现多线程下载,
Android文件下载(实现断点续传)
。一种方式是使用很多个线程分别下载文件的不同部分,最后把所有下载完的文件合并成一个文件。另一种方式是使用java为我们提供的RandomAccessFile类实现多线程的下载。
从性能上分析,第二种方式的存取速度会慢一些,但开发起来较为容易,不需要进行合并文件等操作。
使用图形界面来获取需要下载的内容,并实时更新下载进度条,代码如下所示:
Java代码
packagecom.fly.test;
importandroid.app.Activity;
importjava.io.File;
importjava.net.URL;
importjava.net.URLConnection;
importcom.fly.thread.FileDownloadThread;
importandroid.os.Bundle;
importandroid.os.Environment;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.view.View;
importandroid.view.View.OnClickListener;
importandroid.widget.Button;
importandroid.widget.EditText;
importandroid.widget.ProgressBar;
importandroid.widget.TextView;
/**
*Copyright (C) 2010ideasandroid
*演示android多线程下载
*欢迎访问http://www.ideasandroid.com
*让程序开发不再那么神秘
*/
publicclassFileDownloadDemoextendsActivity{
privateEditTextdownloadUrl;
privateEditTextdownloadFileName;
privateEditTextdownloadThreadNum;
privateButtondownloadBt;
privateProgressBardownloadProgressBar;
privateTextViewprogressMessage;
privateintdownloadedSize=0;
privateintfileSize=0;
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
downloadUrl=(EditText)findViewById(R.id.downloadUrl);
downloadFileName=(EditText)findViewById(R.id.downloadFileName);
downloadThreadNum=(EditText)findViewById(R.id.downloadThreadNum);
progressMessage=(TextView)findViewById(R.id.progressMessage);
downloadBt=(Button)findViewById(R.id.downloadBt);
downloadProgressBar=(ProgressBar)findViewById(R.id.downloadProgressBar);
downloadProgressBar.setVisibility(View.VISIBLE);
downloadProgressBar.setMax(100);
downloadProgressBar.setProgress(0);
downloadBt.setOnClickListener(newOnClickListener() {
publicvoidonClick(Viewv) {
download();
}
});
}
privatevoiddownload(){
//获取SD卡目录
StringdowloadDir=Environment.getExternalStorageDirectory()
+"/ideasdownload/";
Filefile=newFile(dowloadDir);
//创建下载目录
if(!file.exists()) {
file.mkdirs();
}
//读取下载线程数,如果为空,则单线程下载
intdownloadTN=Integer.valueOf("".equals(downloadThreadNum.getText()
.toString())?"1":downloadThreadNum.getText().toString());
//如果下载文件名为空则获取Url尾为文件名
intfileNameStart=downloadUrl.getText().toString().lastIndexOf("/");
StringfileName="".equals(downloadFileName.getText().toString())?downloadUrl
.getText().toString().substring(fileNameStart)
:downloadFileName.getText().toString();
//开始下载前把下载按钮设置为不可用
downloadBt.setClickable(false);
//进度条设为0
downloadProgressBar.setProgress(0);
//启动文件下载线程
newdownloadTask(downloadUrll.getText().toString(),Integer
.valueOf(downloadTN),dowloadDir+fileName).start();
}
Handlerhandler=newHandler() {
@Override
publicvoidhandleMessage(Messagemsg) {
//当收到更新视图消息时,计算已完成下载百分比,同时更新进度条信息
intprogress=(Double.valueOf((downloadedSize*1.0/fileSize*100))).intValue();
if(progress==100) {
downloadBt.setClickable(true);
progressMessage.setText("下载完成!");
}else{
progressMessage.setText("当前进度:"+progress+"%");
}
downloadProgressBar.setProgress(progress);
}
};
/**
*@authorideasandroid
*主下载线程
*/
publicclassdownloadTaskextendsThread{
privateintblockSize,downloadSizeMore;
privateintthreadNum=5;
StringurlStr,threadNo,fileName;
publicdownloadTask(StringurlStr,intthreadNum,StringfileName) {
this.urlStr=urlStr;
this.threadNum=threadNum;
this.fileName=fileName;
}
@Override
publicvoidrun(){
FileDownloadThread[]fds=newFileDownloadThread[threadNum];
try{
URLurl=newURL(urlStr);
URLConnectionconn=url.openConnection();
//获取下载文件的总大小
fileSize=conn.getContentLength();
//计算每个线程要下载的数据量
blockSize=fileSize/threadNum;
//解决整除后百分比计算误差
downloadSizeMore=(fileSize%threadNum);
Filefile=newFile(fileName);
for(inti=0;i
//启动线程,分别下载自己需要下载的部分
FileDownloadThreadfdt=newFileDownloadThread(url,file,
i*blockSize,(i+1)*blockSize-1);
fdt.setName("Thread"+i);
fdt.start();
fds[i]=fdt;
}
booleanfinished=false;
while(!finished) {
//先把整除的余数搞定
downloadedSize=downloadSizeMore;
finished=true;
for(inti=0;i
downloadedSize+=fds[i].getDownloadSize();
if(!fds[i].isFinished()){
finished=false;
}
}
//通知handler去更新视图组件
handler.sendEmptyMessage(0);
//休息1秒后再读取下载进度
sleep(1000);
}
}catch(Exceptione) {
}
}
}
}
Java代码
=================================================================
importjava.io.BufferedInputStream;
importjava.io.File;
importjava.io.IOException;
importjava.io.RandomAccessFile;
importjava.net.URL;
importjava.net.URLConnection;
importandroid.util.Log;
/**
* Copyright (C) 2010ideasandroid
*演示android多线程下载
*让程序开发不再那么神秘
*
*单个下载线程
*/
publicclassFileDownloadThreadextendsThread{
privatestaticfinalintBUFFER_SIZE=1024;
privateURLurl;
privateFilefile;
privateintstartPosition;
privateintendPosition;
privateintcurPosition;
//用于标识当前线程是否下载完成
privatebooleanfinished=false;
privateintdownloadSize=0;
publicFileDownloadThread(URLurl,Filefile,intstartPosition,intendPosition){
this.url=url;
this.file=file;
this.startPosition=startPosition;
this.curPosition=startPosition;
this.endPosition=endPosition;
}
@Override
publicvoidrun(){
BufferedInputStreambis=null;
RandomAccessFilefos=null;
byte[]buf=newbyte[BUFFER_SIZE];
URLConnectioncon=null;
try{
con=url.openConnection();
con.setAllowUserInteraction(true);
//设置当前线程下载的起点,终点
con.setRequestProperty("Range","bytes="+startPosition+"-"+endPosition);
//使用java中的RandomAccessFile对文件进行随机读写操作
fos=newRandomAccessFile(file,"rw");
//设置开始写文件的位置
fos.seek(startPosition);
bis=newBufferedInputStream(con.getInputStream());
//开始循环以流的形式读写文件
while(curPosition
intlen=bis.read(buf,0,BUFFER_SIZE);
if(len==-1) {
break;
}
fos.write(buf,0,len);
curPosition=curPosition+len;
if(curPosition>endPosition) {
downloadSize+=len-(curPosition-endPosition)+1;
}else{
downloadSize+=len;
}
}
//下载完成设为true
this.finished=true;
bis.close();
fos.close();
}catch(IOExceptione) {
Log.d(getName()+" Error:",e.getMessage());
}
}
publicbooleanisFinished(){
returnfinished;
}
publicintgetDownloadSize(){
returndownloadSize;
}
}