Android通过HTTP协议实现断点续传下载实例
整理文档,搜刮出一个Android通过HTTP协议实现断点续传下载的代码,稍微整理精简一下做下分享。
FileDownloader.java
packagecn.itcast.net.download;
importjava.io.File;
importjava.io.RandomAccessFile;
importjava.net.HttpURLConnection;
importjava.net.URL;
importjava.util.LinkedHashMap;
importjava.util.Map;
importjava.util.UUID;
importjava.util.concurrent.ConcurrentHashMap;
importjava.util.regex.Matcher;
importjava.util.regex.Pattern;
importcn.itcast.service.FileService;
importandroid.content.Context;
importandroid.util.Log;
/**
*文件下载器
*FileDownloaderloader=newFileDownloader(context,"http://browse.babasport.com/ejb3/ActivePort.exe",
newFile("D:\\androidsoft\\test"),2);
loader.getFileSize();//得到文件总大小
try{
loader.download(newDownloadProgressListener(){
publicvoidonDownloadSize(intsize){
print("已经下载:"+size);
}
});
}catch(Exceptione){
e.printStackTrace();
}
*/
publicclassFileDownloader{
privatestaticfinalStringTAG="FileDownloader";
privateContextcontext;
privateFileServicefileService;
/*已下载文件长度*/
privateintdownloadSize=0;
/*原始文件长度*/
privateintfileSize=0;
/*线程数*/
privateDownloadThread[]threads;
/*本地保存文件*/
privateFilesaveFile;
/*缓存各线程下载的长度*/
privateMapdata=newConcurrentHashMap();
/*每条线程下载的长度*/
privateintblock;
/*下载路径*/
privateStringdownloadUrl;
/**
*获取线程数
*/
publicintgetThreadSize(){
returnthreads.length;
}
/**
*获取文件大小
*@return
*/
publicintgetFileSize(){
returnfileSize;
}
/**
*累计已下载大小
*@paramsize
*/
protectedsynchronizedvoidappend(intsize){
downloadSize+=size;
}
/**
*更新指定线程最后下载的位置
*@paramthreadId线程id
*@parampos最后下载的位置
*/
protectedsynchronizedvoidupdate(intthreadId,intpos){
this.data.put(threadId,pos);
this.fileService.update(this.downloadUrl,this.data);
}
/**
*构建文件下载器
*@paramdownloadUrl下载路径
*@paramfileSaveDir文件保存目录
*@paramthreadNum下载线程数
*/
publicFileDownloader(Contextcontext,StringdownloadUrl,FilefileSaveDir,intthreadNum){
try{
this.context=context;
this.downloadUrl=downloadUrl;
fileService=newFileService(this.context);
URLurl=newURL(this.downloadUrl);
if(!fileSaveDir.exists())fileSaveDir.mkdirs();
this.threads=newDownloadThread[threadNum];
HttpURLConnectionconn=(HttpURLConnection)url.openConnection();
conn.setConnectTimeout(5*1000);
conn.setRequestMethod("GET");
conn.setRequestProperty("Accept","image/gif,image/jpeg,image/pjpeg,image/pjpeg,application/x-shockwave-flash,application/xaml+xml,application/vnd.ms-xpsdocument,application/x-ms-xbap,application/x-ms-application,application/vnd.ms-excel,application/vnd.ms-powerpoint,application/msword,*/*");
conn.setRequestProperty("Accept-Language","zh-CN");
conn.setRequestProperty("Referer",downloadUrl);
conn.setRequestProperty("Charset","UTF-8");
conn.setRequestProperty("User-Agent","Mozilla/4.0(compatible;MSIE8.0;WindowsNT5.2;Trident/4.0;.NETCLR1.1.4322;.NETCLR2.0.50727;.NETCLR3.0.04506.30;.NETCLR3.0.4506.2152;.NETCLR3.5.30729)");
conn.setRequestProperty("Connection","Keep-Alive");
conn.connect();
printResponseHeader(conn);
if(conn.getResponseCode()==200){
this.fileSize=conn.getContentLength();//根据响应获取文件大小
if(this.fileSize<=0)thrownewRuntimeException("Unkownfilesize");
Stringfilename=getFileName(conn);//获取文件名称
this.saveFile=newFile(fileSaveDir,filename);//构建保存文件
Maplogdata=fileService.getData(downloadUrl);//获取下载记录
if(logdata.size()>0){//如果存在下载记录
for(Map.Entryentry:logdata.entrySet())
data.put(entry.getKey(),entry.getValue());//把各条线程已经下载的数据长度放入data中
}
if(this.data.size()==this.threads.length){//下面计算所有线程已经下载的数据长度
for(inti=0;i0)randOut.setLength(this.fileSize);
randOut.close();
URLurl=newURL(this.downloadUrl);
if(this.data.size()!=this.threads.length){
this.data.clear();
for(inti=0;igetHttpResponseHeader(HttpURLConnectionhttp){
Mapheader=newLinkedHashMap();
for(inti=0;;i++){
Stringmine=http.getHeaderField(i);
if(mine==null)break;
header.put(http.getHeaderFieldKey(i),mine);
}
returnheader;
}
/**
*打印Http头字段
*@paramhttp
*/
publicstaticvoidprintResponseHeader(HttpURLConnectionhttp){
Mapheader=getHttpResponseHeader(http);
for(Map.Entryentry:header.entrySet()){
Stringkey=entry.getKey()!=null?entry.getKey()+":":"";
print(key+entry.getValue());
}
}
privatestaticvoidprint(Stringmsg){
Log.i(TAG,msg);
}
}
DownloadThread.Java
packagecn.itcast.net.download;
importjava.io.File;
importjava.io.InputStream;
importjava.io.RandomAccessFile;
importjava.net.HttpURLConnection;
importjava.net.URL;
importandroid.util.Log;
publicclassDownloadThreadextendsThread{
privatestaticfinalStringTAG="DownloadThread";
privateFilesaveFile;
privateURLdownUrl;
privateintblock;
/*下载开始位置*/
privateintthreadId=-1;
privateintdownLength;
privatebooleanfinish=false;
privateFileDownloaderdownloader;
publicDownloadThread(FileDownloaderdownloader,URLdownUrl,FilesaveFile,intblock,intdownLength,intthreadId){
this.downUrl=downUrl;
this.saveFile=saveFile;
this.block=block;
this.downloader=downloader;
this.threadId=threadId;
this.downLength=downLength;
}
@Override
publicvoidrun(){
if(downLength
DownloadProgressListener.java
packagecn.itcast.net.download;
publicinterfaceDownloadProgressListener{
publicvoidonDownloadSize(intsize);
}
DBOpenHelper.java
packagecn.itcast.service;
importandroid.content.Context;
importandroid.database.sqlite.SQLiteDatabase;
importandroid.database.sqlite.SQLiteOpenHelper;
publicclassDBOpenHelperextendsSQLiteOpenHelper{
privatestaticfinalStringDBNAME="itcast.db";
privatestaticfinalintVERSION=1;
publicDBOpenHelper(Contextcontext){
super(context,DBNAME,null,VERSION);
}
@Override
publicvoidonCreate(SQLiteDatabasedb){
db.execSQL("CREATETABLEIFNOTEXISTSfiledownlog(idintegerprimarykeyautoincrement,downpathvarchar(100),threadidINTEGER,downlengthINTEGER)");
}
@Override
publicvoidonUpgrade(SQLiteDatabasedb,intoldVersion,intnewVersion){
db.execSQL("DROPTABLEIFEXISTSfiledownlog");
onCreate(db);
}
}
FileService.java
packagecn.itcast.service;
importjava.util.HashMap;
importjava.util.Map;
importandroid.content.Context;
importandroid.database.Cursor;
importandroid.database.sqlite.SQLiteDatabase;
/**
*业务bean
*
*/
publicclassFileService{
privateDBOpenHelperopenHelper;
publicFileService(Contextcontext){
openHelper=newDBOpenHelper(context);
}
/**
*获取每条线程已经下载的文件长度
*@parampath
*@return
*/
publicMapgetData(Stringpath){
SQLiteDatabasedb=openHelper.getReadableDatabase();
Cursorcursor=db.rawQuery("selectthreadid,downlengthfromfiledownlogwheredownpath=?",newString[]{path});
Mapdata=newHashMap();
while(cursor.moveToNext()){
data.put(cursor.getInt(0),cursor.getInt(1));
}
cursor.close();
db.close();
returndata;
}
/**
*保存每条线程已经下载的文件长度
*@parampath
*@parammap
*/
publicvoidsave(Stringpath,Mapmap){//intthreadid,intposition
SQLiteDatabasedb=openHelper.getWritableDatabase();
db.beginTransaction();
try{
for(Map.Entryentry:map.entrySet()){
db.execSQL("insertintofiledownlog(downpath,threadid,downlength)values(?,?,?)",
newObject[]{path,entry.getKey(),entry.getValue()});
}
db.setTransactionSuccessful();
}finally{
db.endTransaction();
}
db.close();
}
/**
*实时更新每条线程已经下载的文件长度
*@parampath
*@parammap
*/
publicvoidupdate(Stringpath,Mapmap){
SQLiteDatabasedb=openHelper.getWritableDatabase();
db.beginTransaction();
try{
for(Map.Entryentry:map.entrySet()){
db.execSQL("updatefiledownlogsetdownlength=?wheredownpath=?andthreadid=?",
newObject[]{entry.getValue(),path,entry.getKey()});
}
db.setTransactionSuccessful();
}finally{
db.endTransaction();
}
db.close();
}
/**
*当文件下载完成后,删除对应的下载记录
*@parampath
*/
publicvoiddelete(Stringpath){
SQLiteDatabasedb=openHelper.getWritableDatabase();
db.execSQL("deletefromfiledownlogwheredownpath=?",newObject[]{path});
db.close();
}
}
DownloadActivity.java
packagecn.itcast.download;
importjava.io.File;
importcn.itcast.net.download.DownloadProgressListener;
importcn.itcast.net.download.FileDownloader;
importandroid.app.Activity;
importandroid.os.Bundle;
importandroid.os.Environment;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.view.View;
importandroid.widget.Button;
importandroid.widget.EditText;
importandroid.widget.ProgressBar;
importandroid.widget.TextView;
importandroid.widget.Toast;
publicclassDownloadActivityextendsActivity{
privateEditTextdownloadpathText;
privateTextViewresultView;
privateProgressBarprogressBar;
//当Handler被创建会关联到创建它的当前线程的消息队列,该类用于往消息队列发送消息
//消息队列中的消息由当前线程内部进行处理
privateHandlerhandler=newHandler(){
@Override
publicvoidhandleMessage(Messagemsg){
switch(msg.what){
case1:
progressBar.setProgress(msg.getData().getInt("size"));
floatnum=(float)progressBar.getProgress()/(float)progressBar.getMax();
intresult=(int)(num*100);
resultView.setText(result+"%");
if(progressBar.getProgress()==progressBar.getMax()){
Toast.makeText(DownloadActivity.this,R.string.success,1).show();
}
break;
case-1:
Toast.makeText(DownloadActivity.this,R.string.error,1).show();
break;
}
}
};
@Override
publicvoidonCreate(BundlesavedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
downloadpathText=(EditText)this.findViewById(R.id.downloadpath);
progressBar=(ProgressBar)this.findViewById(R.id.downloadbar);
resultView=(TextView)this.findViewById(R.id.result);
Buttonbutton=(Button)this.findViewById(R.id.button);
button.setOnClickListener(newView.OnClickListener(){
@Override
publicvoidonClick(Viewv){
Stringpath=downloadpathText.getText().toString();
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
download(path,Environment.getExternalStorageDirectory());
}else{
Toast.makeText(DownloadActivity.this,R.string.sdcarderror,1).show();
}
}
});
}
//主线程(UI线程)
//业务逻辑正确,但是该程序运行的时候有问题
//对于显示控件的界面更新只是由UI线程负责,如果是在非UI线程更新控件的属性值,更新后的显示界面不会反映到屏幕上
privatevoiddownload(finalStringpath,finalFilesavedir){
newThread(newRunnable(){
@Override
publicvoidrun(){
FileDownloaderloader=newFileDownloader(DownloadActivity.this,path,savedir,3);
progressBar.setMax(loader.getFileSize());//设置进度条的最大刻度为文件的长度
try{
loader.download(newDownloadProgressListener(){
@Override
publicvoidonDownloadSize(intsize){//实时获知文件已经下载的数据长度
Messagemsg=newMessage();
msg.what=1;
msg.getData().putInt("size",size);
handler.sendMessage(msg);//发送消息
}
});
}catch(Exceptione){
handler.obtainMessage(-1).sendToTarget();
}
}
}).start();
}
}
demo下载:MulThreadDownload_jb51.rar
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。