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);//构建保存文件 Map logdata=fileService.getData(downloadUrl);//获取下载记录 if(logdata.size()>0){//如果存在下载记录 for(Map.Entry entry:logdata.entrySet()) data.put(entry.getKey(),entry.getValue());//把各条线程已经下载的数据长度放入data中 } if(this.data.size()==this.threads.length){//下面计算所有线程已经下载的数据长度 for(inti=0;i 0)randOut.setLength(this.fileSize); randOut.close(); URLurl=newURL(this.downloadUrl); if(this.data.size()!=this.threads.length){ this.data.clear(); for(inti=0;i getHttpResponseHeader(HttpURLConnectionhttp){ Map header=newLinkedHashMap (); for(inti=0;;i++){ Stringmine=http.getHeaderField(i); if(mine==null)break; header.put(http.getHeaderFieldKey(i),mine); } returnheader; } /** *打印Http头字段 *@paramhttp */ publicstaticvoidprintResponseHeader(HttpURLConnectionhttp){ Map header=getHttpResponseHeader(http); for(Map.Entry entry: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(downLengthDownloadProgressListener.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}); Map data=newHashMap (); while(cursor.moveToNext()){ data.put(cursor.getInt(0),cursor.getInt(1)); } cursor.close(); db.close(); returndata; } /** *保存每条线程已经下载的文件长度 *@parampath *@parammap */ publicvoidsave(Stringpath,Map map){//intthreadid,intposition SQLiteDatabasedb=openHelper.getWritableDatabase(); db.beginTransaction(); try{ for(Map.Entry entry: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,Map map){ SQLiteDatabasedb=openHelper.getWritableDatabase(); db.beginTransaction(); try{ for(Map.Entry entry: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
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。