xUtils下载大文件时,文件未下载完整就返回了SUCCESS状态的解决方案
2015-07-02 10:47
344 查看
相信用过xutil的朋友都遇到过我的这种情况xUtils下载大文件时,文件未下载完整就返回了SUCCESS状态。跟踪了代后发现,xutil中的httpclient在流还没读取完时就返回了-1跳出了while循环。之后在xutil中该下载就被标记为已完成但进度却不是100%,要点击继续下载就可以断点下载(好在不会给文件造成什么其他影响,可是也不爽是不?)。
贴下代码:
之后在HttpHandler中修改了代码,解决了这个问题,可是感觉有点治标不治本,哪位朋友有更好的解决方案希望可以分享下!
贴下修改这个BUG的代码,为了方便我把整个类的代码都贴上来了,添加了注释:
贴下代码:
bis = new BufferedInputStream(entity.getContent()); bos = new BufferedOutputStream(fileOutputStream); if (callBackHandler != null && !callBackHandler.updateProgress(total, current, true)) { return targetFile; } byte[] tmp = new byte[4096]; int len; while ((len = bis.read(tmp)) != -1) {//这里返回了-1 bos.write(tmp, 0, len); current += len; if (callBackHandler != null) { if (!callBackHandler.updateProgress(total, current, false)) { return targetFile; } } } bos.flush(); if (callBackHandler != null) { callBackHandler.updateProgress(total, current, true); } } finally { IOUtils.closeQuietly(bis); IOUtils.closeQuietly(bos); }
之后在HttpHandler中修改了代码,解决了这个问题,可是感觉有点治标不治本,哪位朋友有更好的解决方案希望可以分享下!
贴下修改这个BUG的代码,为了方便我把整个类的代码都贴上来了,添加了注释:
public class HttpHandler<T> extends PriorityAsyncTask<Object, Object, Void> implements RequestCallBackHandler { private final AbstractHttpClient client; private final HttpContext context; private HttpRedirectHandler httpRedirectHandler; private long fileLen = 0;//本地已下载文件的大小 private File downloadFile;//本地已下载文件的对象 public void setHttpRedirectHandler(HttpRedirectHandler httpRedirectHandler) { if (httpRedirectHandler != null) { this.httpRedirectHandler = httpRedirectHandler; } } private String requestUrl; private String requestMethod; private HttpRequestBase request; private boolean isUploading = true; private RequestCallBack<T> callback; private int retriedCount = 0; private String fileSavePath = null; private boolean isDownloadingFile = false; private boolean autoResume = false; // Whether the downloading could continue from the point of interruption. private boolean autoRename = false; // Whether rename the file by response header info when the download completely. private String charset; // The default charset of response header info. public HttpHandler(AbstractHttpClient client, HttpContext context, String charset, RequestCallBack<T> callback) { this.client = client; this.context = context; this.callback = callback; this.charset = charset; this.client.setRedirectHandler(notUseApacheRedirectHandler); } private State state = State.WAITING; public State getState() { return state; } private long expiry = HttpCache.getDefaultExpiryTime(); public void setExpiry(long expiry) { this.expiry = expiry; } public void setRequestCallBack(RequestCallBack<T> callback) { this.callback = callback; } public RequestCallBack<T> getRequestCallBack() { return this.callback; } // 执行请求 @SuppressWarnings("unchecked") private ResponseInfo<T> sendRequest(HttpRequestBase request) throws HttpException { HttpRequestRetryHandler retryHandler = client.getHttpRequestRetryHandler(); while (true) { if ((autoResume && isDownloadingFile)) { downloadFile = new File(fileSavePath);//这里提升为全局变量方便后面使用 // long fileLen = 0; fileLen = 0;//这里提升为全局变量方便后面使用 if (downloadFile.isFile() && downloadFile.exists()) { fileLen = downloadFile.length(); } System.out.println("fileLen:"+fileLen); if (fileLen > 0) { request.setHeader("RANGE", "bytes=" + fileLen + "-"); } } boolean retry = true; IOException exception = null; try { requestMethod = request.getMethod(); if (HttpUtils.sHttpCache.isEnabled(requestMethod)) { String result = HttpUtils.sHttpCache.get(requestUrl); if (result != null) { return new ResponseInfo<T>(null, (T) result, true); } } ResponseInfo<T> responseInfo = null; if (!isCancelled()) { HttpResponse response = client.execute(request, context); responseInfo = handleResponse(response); } return responseInfo; } catch (UnknownHostException e) { exception = e; retry = retryHandler.retryRequest(exception, ++retriedCount, context); } catch (IOException e) { exception = e; retry = retryHandler.retryRequest(exception, ++retriedCount, context); } catch (NullPointerException e) { exception = new IOException(e.getMessage()); exception.initCause(e); retry = retryHandler.retryRequest(exception, ++retriedCount, context); } catch (HttpException e) { throw e; } catch (Throwable e) { exception = new IOException(e.getMessage()); exception.initCause(e); retry = retryHandler.retryRequest(exception, ++retriedCount, context); } if (!retry) { throw new HttpException(exception); } } } @Override protected Void doInBackground(Object... params) { if (this.state == State.CANCELLED || params == null || params.length == 0) return null; if (params.length > 3) { fileSavePath = String.valueOf(params[1]); isDownloadingFile = fileSavePath != null; autoResume = (Boolean) params[2]; autoRename = (Boolean) params[3]; } try { if (this.state == State.CANCELLED) return null; // init request & requestUrl request = (HttpRequestBase) params[0]; requestUrl = request.getURI().toString(); if (callback != null) { callback.setRequestUrl(requestUrl); } this.publishProgress(UPDATE_START); lastUpdateTime = SystemClock.uptimeMillis(); ResponseInfo<T> responseInfo = sendRequest(request); if (responseInfo != null) { //检测下载的文件是否完整,防止HttpClient未下载完成既返回-1使得文件state标记 //为SUCCESS而文件并未下载完整的BUG by Charminglee responseInfo = checkoutFileLength(responseInfo); this.publishProgress(UPDATE_SUCCESS, responseInfo); return null; } } catch (HttpException e) { this.publishProgress(UPDATE_FAILURE, e, e.getMessage()); } return null; } /** * 递归检测已下载文件是否完整 * @param responseInfo * @return * @throws HttpException */ private ResponseInfo<T> checkoutFileLength(ResponseInfo<T> responseInfo) throws HttpException {
<span style="white-space:pre"> </span>if(<span style="font-family: Arial, Helvetica, sans-serif;">downloadFile == null</span><span style="font-family: Arial, Helvetica, sans-serif;">) </span><span style="font-family: Arial, Helvetica, sans-serif;">downloadFile = new File(fileSavePath);</span><span style="font-family: Arial, Helvetica, sans-serif;"> </span> System.out.println("本地文件大小:"+downloadFile.length()+" 服务器实际大小:"+(responseInfo.contentLength+fileLen)+" contentLength:"+responseInfo.contentLength+" fileLen"+fileLen); if(downloadFile.length() != (responseInfo.contentLength+fileLen)){ autoResume = true; System.out.println(fileSavePath+"出现了奇葩情况。。。。。。。。。。"); responseInfo = sendRequest(request); checkoutFileLength(responseInfo); } return responseInfo; } private final static int UPDATE_START = 1; private final static int UPDATE_LOADING = 2; private final static int UPDATE_FAILURE = 3; private final static int UPDATE_SUCCESS = 4; @Override @SuppressWarnings("unchecked") protected void onProgressUpdate(Object... values) { if (this.state == State.CANCELLED || values == null || values.length == 0 || callback == null) return; switch ((Integer) values[0]) { case UPDATE_START: this.state = State.STARTED; callback.onStart(); break; case UPDATE_LOADING: if (values.length != 3) return; this.state = State.LOADING; callback.onLoading( Long.valueOf(String.valueOf(values[1])), Long.valueOf(String.valueOf(values[2])), isUploading); break; case UPDATE_FAILURE: if (values.length != 3) return; this.state = State.FAILURE; callback.onFailure((HttpException) values[1], (String) values[2]); break; case UPDATE_SUCCESS: if (values.length != 2) return; this.state = State.SUCCESS; callback.onSuccess((ResponseInfo<T>) values[1]); break; default: break; } } @SuppressWarnings("unchecked") private ResponseInfo<T> handleResponse(HttpResponse response) throws HttpException, IOException { if (response == null) { throw new HttpException("response is null"); } if (isCancelled()) return null; StatusLine status = response.getStatusLine(); int statusCode = status.getStatusCode(); if (statusCode < 300) { Object result = null; HttpEntity entity = response.getEntity(); if (entity != null) { isUploading = false; if (isDownloadingFile) { autoResume = autoResume && OtherUtils.isSupportRange(response); String responseFileName = autoRename ? OtherUtils.getFileNameFromHttpResponse(response) : null; FileDownloadHandler downloadHandler = new FileDownloadHandler(); result = downloadHandler.handleEntity(entity, this, fileSavePath, autoResume, responseFileName); } else { StringDownloadHandler downloadHandler = new StringDownloadHandler(); result = downloadHandler.handleEntity(entity, this, charset); if (HttpUtils.sHttpCache.isEnabled(requestMethod)) { HttpUtils.sHttpCache.put(requestUrl, (String) result, expiry); } } } return new ResponseInfo<T>(response, (T) result, false); } else if (statusCode == 301 || statusCode == 302) { if (httpRedirectHandler == null) { httpRedirectHandler = new DefaultHttpRedirectHandler(); } HttpRequestBase request = httpRedirectHandler.getDirectRequest(response); if (request != null) { return this.sendRequest(request); } } else if (statusCode == 416) { throw new HttpException(statusCode, "maybe the file has downloaded completely"); } else { throw new HttpException(statusCode, status.getReasonPhrase()); } return null; } /** * cancel request task. */ @Override public void cancel() { this.state = State.CANCELLED; if (request != null && !request.isAborted()) { try { request.abort(); } catch (Throwable e) { } } if (!this.isCancelled()) { try { this.cancel(true); } catch (Throwable e) { } } if (callback != null) { callback.onCancelled(); } } private long lastUpdateTime; @Override public boolean updateProgress(long total, long current, boolean forceUpdateUI) { if (callback != null && this.state != State.CANCELLED) { if (forceUpdateUI) { this.publishProgress(UPDATE_LOADING, total, current); } else { long currTime = SystemClock.uptimeMillis(); if (currTime - lastUpdateTime >= callback.getRate()) { lastUpdateTime = currTime; this.publishProgress(UPDATE_LOADING, total, current); } } } return this.state != State.CANCELLED; } public enum State { WAITING(0), STARTED(1), LOADING(2), FAILURE(3), CANCELLED(4), SUCCESS(5); private int value = 0; State(int value) { this.value = value; } public static State valueOf(int value) { switch (value) { case 0: return WAITING; case 1: return STARTED; case 2: return LOADING; case 3: return FAILURE; case 4: return CANCELLED; case 5: return SUCCESS; default: return FAILURE; } } public int value() { return this.value; } } private static final NotUseApacheRedirectHandler notUseApacheRedirectHandler = new NotUseApacheRedirectHandler(); private static final class NotUseApacheRedirectHandler implements RedirectHandler { @Override public boolean isRedirectRequested(HttpResponse httpResponse, HttpContext httpContext) { return false; } @Override public URI getLocationURI(HttpResponse httpResponse, HttpContext httpContext) throws ProtocolException { return null; } } }
相关文章推荐
- mac下Cornerstone显示日志问题 Cound not contact repository to read the latest log entries
- 内存中的五大分区
- log文件超过2G导致程序崩
- 单链表的操作
- 微博SDK 分享以后无法返回
- hdu2955 Robberies 01背包的变形
- python多线程
- Spring中<context:annotation-config/>的作用
- Http协议
- 使用Lua来扩展C++程序的方法
- PHP之冒泡排序
- [Leetcode题解]004 Median of Two Sorted Arrays
- 简述Java中,GUI的事件驱动模式
- IOCP的封装和使用
- display的值以及作用。
- 最近很火!一名移动互联网员工写给老婆的信
- 我的退货申请-留此文档作为纪念.
- c语言结构体中保存函数指针的用法
- jsp页面中jstl标签详解
- 原型模式