項目中用到的,要求一次下載30張圖片。開始時使用谷歌bitmap fun中提供的ImageFetcher來下載,可是發現一個蛋疼無比現象,圖片老是莫名其妙的少幾張。
java
排除了圖片地址存在無效連接外,懷疑是併發下載線程個數太多,線程池滿了之後,使用拋棄策略將之前的下載線程拋棄了。android
求人不如求己,本身寫一個吧。併發
在這裏使用線程池,支持併發下載。線程池能夠本身選擇,使用newSingleThreadExecutor,newFixedThreadPool,newCachedThreadPool中的任意一種。使用時,本身實現監聽器,當監聽下載個數與url集合的個數相同時,會回調監聽器的onSuccess()方法。ide
源碼以下,但願你們指正this
import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLEncoder; import java.util.List; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.RejectedExecutionException; import android.util.Log; /** * 批量圖片下載類 無需與界面交互的下載類 * * @Description: * * @author- liubing * @create- 2013-5 -6 * @modify by: * @modify- time */ public class DownloadService { private static String TAG = "DownloadService" ; public static final int IO_BUFFER_SIZE = 8 * 1024; private static final String CACHE_FILENAME_PREFIX = "cache_"; private static ExecutorService SINGLE_TASK_EXECUTOR = null; private static ExecutorService LIMITED_TASK_EXECUTOR = null; private static final ExecutorService FULL_TASK_EXECUTOR = null; private static final ExecutorService DEFAULT_TASK_EXECUTOR ; private static Object lock = new Object(); static { // SINGLE_TASK_EXECUTOR = (ExecutorService) // Executors.newSingleThreadExecutor(); LIMITED_TASK_EXECUTOR = (ExecutorService) Executors . newFixedThreadPool(1); // FULL_TASK_EXECUTOR = (ExecutorService) // Executors.newCachedThreadPool(); DEFAULT_TASK_EXECUTOR = LIMITED_TASK_EXECUTOR ; }; // 下載狀態監聽,提供回調 DownloadStateListener listener; // 下載目錄 private String downloadPath; // 下載連接集合 private List<String> listURL; // 下載個數 private int size = 0; // 下載完成回調接口 public interface DownloadStateListener { public void onFinish(); public void onFailed(); } public DownloadService(String downloadPath, List<String> listURL, DownloadStateListener listener) { this.downloadPath = downloadPath; this.listURL = listURL; this.listener = listener; } /** * 暫未提供設置 */ public void setDefaultExecutor() { } /** * 開始下載 */ public void startDownload() { // 首先檢測path是否存在 File downloadDirectory = new File(downloadPath ); if (!downloadDirectory.exists()) { downloadDirectory.mkdirs(); } for (final String url : listURL) { //捕獲線程池拒絕執行異常 try { // 線程放入線程池 DEFAULT_TASK_EXECUTOR.execute(new Runnable() { @Override public void run() { downloadBitmap(url); } }); } catch (RejectedExecutionException e) { e.printStackTrace(); Log. e(TAG, "thread pool rejected error"); listener.onFailed(); } catch (Exception e) { e.printStackTrace(); listener.onFailed(); } } } /** * 下載圖片 * * @param urlString * @return */ private File downloadBitmap(String urlString) { String fileName = urlString; // 圖片命名方式 final File cacheFile = new File(createFilePath(new File( downloadPath), fileName)); HttpURLConnection urlConnection = null; BufferedOutputStream out = null; try { final URL url = new URL(urlString); urlConnection = (HttpURLConnection) url.openConnection(); final InputStream in = new BufferedInputStream( urlConnection.getInputStream(), IO_BUFFER_SIZE); out = new BufferedOutputStream(new FileOutputStream(cacheFile), IO_BUFFER_SIZE); int b; while ((b = in.read()) != -1) { out.write(b); } // 每下載成功一個,統計一下圖片個數 statDownloadNum(); return cacheFile; } catch (final IOException e) { // 有一個下載失敗,則表示批量下載沒有成功 Log. e(TAG, "download " + urlString + " error"); listener.onFailed(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } if (out != null ) { try { out.close(); } catch (final IOException e) { Log. e(TAG, "Error in downloadBitmap - " + e); } } } return null ; } /** * Creates a constant cache file path given a target cache directory and an * image key. * * @param cacheDir * @param key * @return */ public static String createFilePath(File cacheDir, String key) { try { // Use URLEncoder to ensure we have a valid filename, a tad hacky // but it will do for // this example return cacheDir.getAbsolutePath() + File.separator + CACHE_FILENAME_PREFIX + URLEncoder.encode(key.replace("*", ""), "UTF-8" ); } catch (final UnsupportedEncodingException e) { Log. e(TAG, "createFilePath - " + e); } return null ; } /** * 統計下載個數 */ private void statDownloadNum() { synchronized (lock ) { size++; if (size == listURL .size()) { Log. d(TAG, "download finished total " + size); // 釋放資源 DEFAULT_TASK_EXECUTOR.shutdownNow(); // 若是下載成功的個數與列表中 url個數一致,說明下載成功 listener.onFinish(); // 下載成功回調 } } } }
使用方法以下:url
new DownloadService( "/mnt/sdcard/test", listUrl, new DownloadStateListener() { @Override public void onFinish() { //圖片下載成功後,實現您的代碼 } @Override public void onFailed() { //圖片下載成功後,實現您的代碼 } }).startDownload();