断点下载
16lz
2021-01-24
很多时候我们需要在Android设备上下载远程服务器上的文件进安装,前两天晚上我看到一个视频,写了两个晚上,大概理解一下。 直接通过Android提供的Http类访问远程服务器,这里AndroidHttpClient是SDK 2.2中新出的方法,
下载断点文件。
下面让我们看一下图先。
- 让我们看一下代码的实现方法。
- packagecom.smart.db;
- 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
- */
- publicMap<Integer,Integer>getData(Stringpath){
- SQLiteDatabasedb=openHelper.getReadableDatabase();
- Cursorcursor=db.rawQuery("selectthreadid,downlengthfromSmartFileDownlogwheredownpath=?",newString[]{path});
- Map<Integer,Integer>data=newHashMap<Integer,Integer>();
- while(cursor.moveToNext()){
- data.put(cursor.getInt(0),cursor.getInt(1));
- }
- cursor.close();
- db.close();
- returndata;
- }
- /**
- *保存每条线程已经下载的文件长度
- *@parampath
- *@parammap
- */
- publicvoidsave(Stringpath,Map<Integer,Integer>map){//intthreadid,intposition
- SQLiteDatabasedb=openHelper.getWritableDatabase();
- db.beginTransaction();
- try{
- for(Map.Entry<Integer,Integer>entry:map.entrySet()){
- db.execSQL("insertintoSmartFileDownlog(downpath,threadid,downlength)values(?,?,?)",
- newObject[]{path,entry.getKey(),entry.getValue()});
- }
- db.setTransactionSuccessful();
- }finally{
- db.endTransaction();
- }
- db.close();
- }
- /**
- *实时更新每条线程已经下载的文件长度
- *@parampath
- *@parammap
- */
- publicvoidupdate(Stringpath,Map<Integer,Integer>map){
- SQLiteDatabasedb=openHelper.getWritableDatabase();
- db.beginTransaction();
- try{
- for(Map.Entry<Integer,Integer>entry:map.entrySet()){
- db.execSQL("updateSmartFileDownlogsetdownlength=?wheredownpath=?andthreadid=?",
- newObject[]{entry.getValue(),path,entry.getKey()});
- }
- db.setTransactionSuccessful();
- }finally{
- db.endTransaction();
- }
- db.close();
- }
- /**
- *当文件下载完成后,删除对应的下载记录
- *@parampath
- */
- publicvoiddelete(Stringpath){
- SQLiteDatabasedb=openHelper.getWritableDatabase();
- db.execSQL("deletefromSmartFileDownlogwheredownpath=?",newObject[]{path});
- db.close();
- }
- }
- packagecom.smart.impl;
- 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;
- importandroid.content.Context;
- importandroid.util.Log;
- importcom.smart.db.FileService;
- /**
- *文件下载器
- *@author[email protected]
- */
- publicclassSmartFileDownloader{
- privatestaticfinalStringTAG="SmartFileDownloader";
- privateContextcontext;
- privateFileServicefileService;
- /*已下载文件长度*/
- privateintdownloadSize=0;
- /*原始文件长度*/
- privateintfileSize=0;
- /*线程数*/
- privateSmartDownloadThread[]threads;
- /*本地保存文件*/
- privateFilesaveFile;
- /*缓存各线程下载的长度*/
- privateMap<Integer,Integer>data=newConcurrentHashMap<Integer,Integer>();
- /*每条线程下载的长度*/
- privateintblock;
- /*下载路径*/
- privateStringdownloadUrl;
- /**
- *获取线程数
- */
- publicintgetThreadSize(){
- returnthreads.length;
- }
- /**
- *获取文件大小
- *@return
- */
- publicintgetFileSize(){
- returnfileSize;
- }
- /**
- *累计已下载大小
- *@paramsize
- */
- protectedsynchronizedvoidappend(intsize){
- downloadSize+=size;
- }
- /**
- *更新指定线程最后下载的位置
- *@paramthreadId线程id
- *@parampos最后下载的位置
- */
- protectedvoidupdate(intthreadId,intpos){
- this.data.put(threadId,pos);
- }
- /**
- *保存记录文件
- */
- protectedsynchronizedvoidsaveLogFile(){
- this.fileService.update(this.downloadUrl,this.data);
- }
- /**
- *构建文件下载器
- *@paramdownloadUrl下载路径
- *@paramfileSaveDir文件保存目录
- *@paramthreadNum下载线程数
- */
- publicSmartFileDownloader(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=newSmartDownloadThread[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<Integer,Integer>logdata=fileService.getData(downloadUrl);
- if(logdata.size()>0){
- for(Map.Entry<Integer,Integer>entry:logdata.entrySet())
- data.put(entry.getKey(),entry.getValue());
- }
- this.block=(this.fileSize%this.threads.length)==0?this.fileSize/this.threads.length:this.fileSize/this.threads.length+1;
- if(this.data.size()==this.threads.length){
- for(inti=0;i<this.threads.length;i++){
- this.downloadSize+=this.data.get(i+1);
- }
- print("已经下载的长度"+this.downloadSize);
- }
- }else{
- thrownewRuntimeException("servernoresponse");
- }
- }catch(Exceptione){
- print(e.toString());
- thrownewRuntimeException("don'tconnectionthisurl");
- }
- }
- /**
- *获取文件名
- */
- privateStringgetFileName(HttpURLConnectionconn){
- Stringfilename=this.downloadUrl.substring(this.downloadUrl.lastIndexOf('/')+1);
- if(filename==null||"".equals(filename.trim())){//如果获取不到文件名称
- for(inti=0;;i++){
- Stringmine=conn.getHeaderField(i);
- if(mine==null)break;
- if("content-disposition".equals(conn.getHeaderFieldKey(i).toLowerCase())){
- Matcherm=Pattern.compile(".*filename=(.*)").matcher(mine.toLowerCase());
- if(m.find())returnm.group(1);
- }
- }
- filename=UUID.randomUUID()+".tmp";//默认取一个文件名
- }
- returnfilename;
- }
- /**
- *开始下载文件
- *@paramlistener监听下载数量的变化,如果不需要了解实时下载的数量,可以设置为null
- *@return已下载文件大小
- *@throwsException
- */
- publicintdownload(SmartDownloadProgressListenerlistener)throwsException{
- try{
- RandomAccessFilerandOut=newRandomAccessFile(this.saveFile,"rw");
- if(this.fileSize>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<this.threads.length;i++){
- this.data.put(i+1,0);
- }
- }
- for(inti=0;i<this.threads.length;i++){
- intdownLength=this.data.get(i+1);
- if(downLength<this.block&&this.downloadSize<this.fileSize){//该线程未完成下载时,继续下载
- this.threads=newSmartDownloadThread(this,url,this.saveFile,this.block,this.data.get(i+1),i+1);
- this.threads.setPriority(7);
- this.threads.start();
- }else{
- this.threads=null;
- }
- }
- this.fileService.save(this.downloadUrl,this.data);
- booleannotFinish=true;//下载未完成
- while(notFinish){//循环判断是否下载完毕
- Thread.sleep(900);
- notFinish=false;//假定下载完成
- for(inti=0;i<this.threads.length;i++){
- if(this.threads!=null&&!this.threads.isFinish()){
- notFinish=true;//下载没有完成
- if(this.threads.getDownLength()==-1){//如果下载失败,再重新下载
- this.threads=newSmartDownloadThread(this,url,this.saveFile,this.block,this.data.get(i+1),i+1);
- this.threads.setPriority(7);
- this.threads.start();
- }
- }
- }
- if(listener!=null)listener.onDownloadSize(this.downloadSize);
- }
- fileService.delete(this.downloadUrl);
- }catch(Exceptione){
- print(e.toString());
- thrownewException("filedownloadfail");
- }
- returnthis.downloadSize;
- }
- /**
- *获取Http响应头字段
- *@paramhttp
- *@return
- */
- publicstaticMap<String,String>getHttpResponseHeader(HttpURLConnectionhttp){
- Map<String,String>header=newLinkedHashMap<String,String>();
- for(inti=0;;i++){
- Stringmine=http.getHeaderField(i);
- if(mine==null)break;
- header.put(http.getHeaderFieldKey(i),mine);
- }
- returnheader;
- }
- /**
- *打印Http头字段
- *@paramhttp
- */
- publicstaticvoidprintResponseHeader(HttpURLConnectionhttp){
- Map<String,String>header=getHttpResponseHeader(http);
- for(Map.Entry<String,String>entry:header.entrySet()){
- Stringkey=entry.getKey()!=null?entry.getKey()+":":"";
- print(key+entry.getValue());
- }
- }
- //打印日志
- privatestaticvoidprint(Stringmsg){
- Log.i(TAG,msg);
- }
- }
- packagecom.smart.impl;
- importjava.io.File;
- importjava.io.InputStream;
- importjava.io.RandomAccessFile;
- importjava.net.HttpURLConnection;
- importjava.net.URL;
- importandroid.util.Log;
- publicclassSmartDownloadThreadextendsThread{
- privatestaticfinalStringTAG="SmartDownloadThread";
- privateFilesaveFile;
- privateURLdownUrl;
- privateintblock;
- /**下载开始位置*/
- privateintthreadId=-1;
- privateintdownLength;
- privatebooleanfinish=false;
- privateSmartFileDownloaderdownloader;
- publicSmartDownloadThread(SmartFileDownloaderdownloader,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<block){//未下载完成
- try{
- HttpURLConnectionhttp=(HttpURLConnection)downUrl.openConnection();
- http.setConnectTimeout(5*1000);
- http.setRequestMethod("GET");
- http.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,*/*");
- http.setRequestProperty("Accept-Language","zh-CN");
- http.setRequestProperty("Referer",downUrl.toString());
- http.setRequestProperty("Charset","UTF-8");
- intstartPos=block*(threadId-1)+downLength;//开始位置
- intendPos=block*threadId-1;//结束位置
- http.setRequestProperty("Range","bytes="+startPos+"-"+endPos);//设置获取实体数据的范围
- http.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)");
- http.setRequestProperty("Connection","Keep-Alive");
- InputStreaminStream=http.getInputStream();
- byte[]buffer=newbyte[1024];
- intoffset=0;
- print("Thread"+this.threadId+"startdownloadfromposition"+startPos);
- RandomAccessFilethreadfile=newRandomAccessFile(this.saveFile,"rwd");
- threadfile.seek(startPos);
- while((offset=inStream.read(buffer,0,1024))!=-1){
- threadfile.write(buffer,0,offset);
- downLength+=offset;
- downloader.update(this.threadId,downLength);
- downloader.saveLogFile();
- downloader.append(offset);
- }
- threadfile.close();
- inStream.close();
- print("Thread"+this.threadId+"downloadfinish");
- this.finish=true;
- }catch(Exceptione){
- this.downLength=-1;
- print("Thread"+this.threadId+":"+e);
- }
- }
- }
- privatestaticvoidprint(Stringmsg){
- Log.i(TAG,msg);
- }
- /**
- *下载是否完成
- *@return
- */
- publicbooleanisFinish(){
- returnfinish;
- }
- /**
- *已经下载的内容大小
- *@return如果返回值为-1,代表下载失败
- */
- publiclonggetDownLength(){
- returndownLength;
- }
- }
- packagecom.smart.activoty.download;
- importjava.io.File;
- 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;
- importcom.smart.impl.SmartDownloadProgressListener;
- importcom.smart.impl.SmartFileDownloader;
- publicclassSmartDownloadActivityextendsActivity{
- privateProgressBardownloadbar;
- privateEditTextpathText;
- privateTextViewresultView;
- privateHandlerhandler=newHandler(){
- @Override//信息
- publicvoidhandleMessage(Messagemsg){
- switch(msg.what){
- case1:
- intsize=msg.getData().getInt("size");
- downloadbar.setProgress(size);
- floatresult=(float)downloadbar.getProgress()/(float)downloadbar.getMax();
- intp=(int)(result*100);
- resultView.setText(p+"%");
- if(downloadbar.getProgress()==downloadbar.getMax())
- Toast.makeText(SmartDownloadActivity.this,R.string.success,1).show();
- break;
- case-1:
- Toast.makeText(SmartDownloadActivity.this,R.string.error,1).show();
- break;
- }
- }
- };
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- Buttonbutton=(Button)this.findViewById(R.id.button);
- downloadbar=(ProgressBar)this.findViewById(R.id.downloadbar);
- pathText=(EditText)this.findViewById(R.id.path);
- resultView=(TextView)this.findViewById(R.id.result);
- button.setOnClickListener(newView.OnClickListener(){
- @Override
- publicvoidonClick(Viewv){
- Stringpath=pathText.getText().toString();
- if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
- Filedir=Environment.getExternalStorageDirectory();//文件保存目录
- download(path,dir);
- }else{
- Toast.makeText(SmartDownloadActivity.this,R.string.sdcarderror,1).show();
- }
- }
- });
- }
- //对于UI控件的更新只能由主线程(UI线程)负责,如果在非UI线程更新UI控件,更新的结果不会反映在屏幕上,某些控件还会出错
- privatevoiddownload(finalStringpath,finalFiledir){
- newThread(newRunnable(){
- @Override
- publicvoidrun(){
- try{
- SmartFileDownloaderloader=newSmartFileDownloader(SmartDownloadActivity.this,path,dir,3);
- intlength=loader.getFileSize();//获取文件的长度
- downloadbar.setMax(length);
- loader.download(newSmartDownloadProgressListener(){
- @Override
- publicvoidonDownloadSize(intsize){//可以实时得到文件下载的长度
- Messagemsg=newMessage();
- msg.what=1;
- msg.getData().putInt("size",size);
- handler.sendMessage(msg);
- }});
- }catch(Exceptione){
- Messagemsg=newMessage();//信息提示
- msg.what=-1;
- msg.getData().putString("error","下载失败");//如果下载错误,显示提示失败!
- handler.sendMessage(msg);
- }
- }
- }).start();//开始
- }
- }
更多相关文章
- android-pull方式解析xml文件以及XML文件的序列化
- android 实现左右滑动效果
- Android的Recovery中font_10x10.h字库文件制作
- android R cannot be resolved to a variable
- Android(安卓)APK反编译详解
- Android(安卓)面试题(5):谈谈 Handler 机制和原理?
- Android(安卓)Spinner
- APEX - Android(安卓)Q
- Android的Zipalign优化