Java tutorial
/** * Copyright (c) 2012-2013, Michael Yang ?? (www.yangfuhai.com). * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.miku.framelite.httpx.core; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.UnknownHostException; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import java.util.concurrent.atomic.AtomicInteger; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.HttpResponseException; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.AbstractHttpClient; import com.miku.framelite.httpx.IDownloadHandler; import android.os.AsyncTask; import android.os.SystemClock; import android.text.TextUtils; public class DownloadHandler extends AsyncTask<Object, Object, Object> implements IDownloadHandler { private static final String TAG = DownloadHandler.class.getSimpleName(); private static int httpThreadCount = 3;// http? private AbstractHttpClient client; private DownloadCallback callback; private String targetUrl = null; // private boolean isResume = false; // ? private boolean stopFlag = false; private boolean isStop = false; private static final ThreadFactory sThreadFactory = new ThreadFactory() { private final AtomicInteger mCount = new AtomicInteger(1); public Thread newThread(Runnable r) { Thread tread = new Thread(r, "Http #" + mCount.getAndIncrement()); tread.setPriority(Thread.NORM_PRIORITY - 1); return tread; } }; public static final Executor MUTIPLE_EXECUTORS = Executors.newFixedThreadPool(httpThreadCount, sThreadFactory); public DownloadHandler(AbstractHttpClient client, DownloadCallback callback) { this.client = client; this.callback = callback; } private void makeRequestWithRetries(HttpUriRequest request) throws Exception { if (isResume && targetUrl != null) { File downloadFile = new File(targetUrl); long fileLen = 0; if (downloadFile.isFile() && downloadFile.exists()) { fileLen = downloadFile.length(); } if (fileLen > 0) { request.setHeader("RANGE", "bytes=" + fileLen + "-"); } } Exception cause = null; try { if (!isCancelled()) { HttpResponse response = client.execute(request/* , context */); if (!isCancelled()) { handleResponse(response); } } } catch (UnknownHostException e) { e.printStackTrace(); publishProgress(UPDATE_FAILURE, e, 0, "unknownHostExceptioncan't resolve host"); cause = e; } catch (IOException e) { e.printStackTrace(); cause = e; } catch (NullPointerException e) { e.printStackTrace(); // HttpClient 4.0.x ?bug // http://code.google.com/p/android/issues/detail?id=5255 cause = new IOException("NPE in HttpClient" + e.getMessage()); } catch (Exception e) { e.printStackTrace(); cause = e; } if (cause != null) { throw cause; } } @Override protected Object doInBackground(Object... params) { if (params != null && params.length == 3) { targetUrl = String.valueOf(params[1]); isResume = (Boolean) params[2]; } try { publishProgress(UPDATE_START); // makeRequestWithRetries((HttpUriRequest) params[0]); } catch (Exception e) { publishProgress(UPDATE_FAILURE, e, 0, e.getMessage()); // ? e.printStackTrace(); } finally { isStop = true; } return null; } @Override protected void onPostExecute(Object result) { super.onPostExecute(result); isStop = true; } 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 protected void onProgressUpdate(Object... values) { int update = Integer.valueOf(String.valueOf(values[0])); switch (update) { case UPDATE_START: if (callback != null) callback.onStart(); break; case UPDATE_LOADING: if (callback != null) callback.onLoading(Long.valueOf(String.valueOf(values[1])), Long.valueOf(String.valueOf(values[2]))); break; case UPDATE_FAILURE: if (callback != null) callback.onFailure((Exception) values[1], (Integer) values[2], (String) values[3]); break; case UPDATE_SUCCESS: if (callback != null) callback.onSuccess((File) values[1]); break; default: break; } super.onProgressUpdate(values); } public boolean isStop() { return isStop; } /** * @param stop * ? */ public void stop() { stopFlag = true; } private void handleResponse(HttpResponse response) { StatusLine status = response.getStatusLine(); if (status.getStatusCode() >= 300) { String errorMsg = "response status error code:" + status.getStatusCode(); if (status.getStatusCode() == 416 && isResume) { errorMsg += " \n maybe you have download complete."; } publishProgress(UPDATE_FAILURE, new HttpResponseException(status.getStatusCode(), status.getReasonPhrase()), status.getStatusCode(), errorMsg); } else { try { HttpEntity entity = response.getEntity(); Object responseBody = null; if (entity != null) { time = SystemClock.uptimeMillis(); if (targetUrl != null) { responseBody = handleEntity(entity, targetUrl, isResume); } } publishProgress(UPDATE_SUCCESS, responseBody); } catch (IOException e) { publishProgress(UPDATE_FAILURE, e, 0, e.getMessage()); } } } private long time; public void downloadNotice(long count, long current, boolean mustNoticeUI) { if (callback != null) { if (mustNoticeUI) { publishProgress(UPDATE_LOADING, count, current); } else { long thisTime = SystemClock.uptimeMillis(); // ?500ms if (thisTime - time >= 500) { time = thisTime; publishProgress(UPDATE_LOADING, count, current); } } } } public Object handleEntity(HttpEntity entity, String target, boolean isResume) throws IOException { if (TextUtils.isEmpty(target) || target.trim().length() == 0) return null; File targetFile = new File(target); if (!targetFile.exists()) { targetFile.createNewFile(); } if (stopFlag) { return targetFile; } long current = 0; current = targetFile.length(); // orz??? if (current == entity.getContentLength()) { downloadNotice(current, current, true); return targetFile; } FileOutputStream os = null; InputStream input = null; try { if (isResume) { os = new FileOutputStream(target, true); } else { os = new FileOutputStream(target); } if (stopFlag) { return targetFile; } input = entity.getContent(); long count = entity.getContentLength() + current; if (current >= count || stopFlag) { return targetFile; } int readLen = 0; byte[] buffer = new byte[1024]; while (!stopFlag && !(current >= count) && ((readLen = input.read(buffer, 0, 1024)) > 0)) {// ? os.write(buffer, 0, readLen); current += readLen; downloadNotice(count, current, false); } downloadNotice(count, current, true); if (stopFlag && current < count) { // ? IOException e = new IOException("user stop download thread"); publishProgress(UPDATE_FAILURE, e, 0, e.getMessage()); // ? return targetFile; } } finally { if (os != null) { os.close(); } if (input != null) { input.close(); } } return targetFile; } }