Volley扩展——文件断点下载(支持下载进度)

      volley同样不适合大文件的下载,只能自己扩展了,我这里参考了Netroid,有兴趣的可以去分析下,文件下载模仿了图片的加载方式,添加了两个类分别是FileDownloadRequest和FileDownloader。断点续传是根据http头里的Range 和Content-Range实现.

            Range用于请求头中,指定第一个字节的位置和最后一个字节的位置,一般格式:

            Range:(unit=first byte pos)-[last byte pos] 

           Content-Range用于响应头,指定整个实体中的一部分的插入位置,他也指示了整个实体的长度。在服务器向客户返回一个部分响应,它必须描述响应覆盖的范围和整个实体长度。一般格式: 

           Content-Range: bytes (unit first byte pos) - [last byte pos]/[entity legth] 

例如:

           Range: bytes=0-801       一般下载整个文件是 0-,没有后边的801

          Content-Range: bytes 2753525-41526127/41526128        斜杠后边的是文件总大小

关键代码:

[html]  view plain  copy
  1. public Map<String, String> getHeaders() throws AuthFailureError {  
  2.         Map<String,String> map = new HashMap<String,String>();  
  3.         map.put("Range", "bytes=" + mTemporaryFile.length() + "-");  
  4.         return map;  
  5.     }  

[html]  view plain  copy
  1. public byte[] handleResponse(HttpResponse response, ResponseDelivery delivery) throws IOException, ServerError {  
  2.         // Content-Length might be negative when use HttpURLConnection because it default header Accept-Encoding is gzip,  
  3.         // we can force set the Accept-Encoding as identity in prepare() method to slove this problem but also disable gzip response.  
  4.         HttpEntity entity = response.getEntity();  
  5.         long fileSize = entity.getContentLength();  
  6.         if (fileSize <= 0) {  
  7.             VolleyLog.d("Response doesn't present Content-Length!");  
  8.         }  
  9.   
  10.         long downloadedSize = mTemporaryFile.length();  
  11.         boolean isSupportRange = HttpUtils.isSupportRange(response);  
  12.         if (isSupportRange) {  
  13.             fileSize += downloadedSize;  
  14.   
  15.             // Verify the Content-Range Header, to ensure temporary file is part of the whole file.  
  16.             // Sometime, temporary file length add response content-length might greater than actual file length,  
  17.             // in this situation, we consider the temporary file is invalid, then throw an exception.  
  18.             String realRangeValue = HttpUtils.getHeader(response, "Content-Range");  
  19.             Log.e("FileDownloadRequest","response header Content-Range:" + realRangeValue);  
  20.             // response Content-Range may be null when "Range=bytes=0-"  
  21.             if (!TextUtils.isEmpty(realRangeValue)) {  
  22.                 String assumeRangeValue = "bytes " + downloadedSize + "-" + (fileSize - 1);  
  23.                 Log.e("FileDownloadRequest","assumeRangeValue:" + assumeRangeValue);  
  24.                 if (TextUtils.indexOf(realRangeValue, assumeRangeValue) == -1) {  
  25.                     throw new IllegalStateException(  
  26.                             "The Content-Range Header is invalid Assume[" + assumeRangeValue + "] vs Real[" + realRangeValue + "], " +  
  27.                                     "please remove the temporary file [" + mTemporaryFile + "].");  
  28.                 }  
  29.             }  
  30.         }  
  31.   
  32.         // Compare the store file size(after download successes have) to server-side Content-Length.  
  33.         // temporary file will rename to store file after download success, so we compare the  
  34.         // Content-Length to ensure this request already download or not.  
  35.         if (fileSize > 0 && mStoreFile.length() == fileSize) {  
  36.             // Rename the store file to temporary file, mock the download success. ^_^  
  37.             mStoreFile.renameTo(mTemporaryFile);  
  38.   
  39.             // Deliver download progress.  
  40.             delivery.postProgress(this, fileSize, fileSize);  
  41.             return null;  
  42.         }  
  43.   
  44.         RandomAccessFile tmpFileRaf = new RandomAccessFile(mTemporaryFile, "rw");  
  45.   
  46.         // If server-side support range download, we seek to last point of the temporary file.  
  47.         if (isSupportRange) {  
  48.             tmpFileRaf.seek(downloadedSize);  
  49.         } else {  
  50.             // If not, truncate the temporary file then start download from beginning.  
  51.             tmpFileRaf.setLength(0);  
  52.             downloadedSize = 0;  
  53.         }  
  54.   
  55.         try {  
  56.             InputStream in = entity.getContent();  
  57.             // Determine the response gzip encoding, support for HttpClientStack download.  
  58.             if (HttpUtils.isGzipContent(response) && !(in instanceof GZIPInputStream)) {  
  59.                 in = new GZIPInputStream(in);  
  60.             }  
  61.             byte[] buffer = new byte[6 * 1024]; // 6K buffer  
  62.             int offset;  
  63.   
  64.             while ((offset = in.read(buffer)) != -1) {  
  65.                 tmpFileRaf.write(buffer, 0, offset);  
  66.   
  67.                 downloadedSize += offset;  
  68.                 delivery.postProgress(this, fileSize, downloadedSize);  
  69.   
  70.                 if (isCanceled()) {  
  71.                     delivery.postCancel(this);  
  72.                     break;  
  73.                 }  
  74.             }  
  75.         } finally {  
  76.             try {  
  77.                 // Close the InputStream and release the resources by "consuming the content".  
  78.                 if (entity != null) entity.consumeContent();  
  79.             } catch (Exception e) {  
  80.                 // This can happen if there was an exception above that left the entity in  
  81.                 // an invalid state.  
  82.                 VolleyLog.v("Error occured when calling consumingContent");  
  83.             }  
  84.             tmpFileRaf.close();  
  85.         }  
  86.   
  87.         return null;  
  88.     }  

demo连接: http://download.csdn.net/detail/s569646547/9098291
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值