封装一个工具类,搞定图片批量下载

项目中用到的,要求一次下载30张图片。开始时使用谷歌bitmap fun中提供的ImageFetcher来下载,但是发现一个蛋疼无比现象,图片总是莫名其妙的少几张。

排除了图片地址存在无效链接外,怀疑是并发下载线程个数太多,线程池满了以后,使用抛弃策略将以前的下载线程抛弃了。

求人不如求己,自己写一个吧。

在这里使用线程池,支持并发下载。线程池可以自己选择,使用newSingleThreadExecutor,newFixedThreadPool,newCachedThreadPool中的任意一种。使用时,自己实现监听器,当监听下载个数与url集合的个数相同时,会回调监听器的onSuccess()方法。

源码如下,希望大家指正

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(); // 下载成功回调
              }
          }
     }
}

使用方法如下:

new DownloadService( "/mnt/sdcard/test", listUrl, new DownloadStateListener() {
              
               @Override
               public void onFinish() {
                    //图片下载成功后,实现您的代码
                   
              }
              
               @Override
               public void onFailed() {
                    //图片下载成功后,实现您的代码
                   
              }
          }).startDownload();
时间: 2024-10-19 06:42:52

封装一个工具类,搞定图片批量下载的相关文章

配置简单功能强大的excel工具类搞定excel导入导出工具类(一)

对于J2EE项目导入导出Excel是最普通和实用功能,本工具类使用步骤简单,功能强大,只需要对实体类进行简单的注解就能实现导入导出功能,导入导出操作的都是实体对象. 请看一下这个类都有哪些功能:????? 1.实体属性配置了注解就能导出到excel中,每个属性都对应一列.????? 2.列名称可以通过注解配置.????? 3.导出到哪一列可以通过注解配置.????? 4.鼠标移动到该列时提示信息可以通过注解配置.????? 5.用注解设置只能下拉选择不能随意填写功能.???? ? 6.用注解设置

Swift:简单封装一个工具类模板

创建模板类(封装一个类)新建一个名字叫做 Product 的类 Product.swift File 的内容 class Product { var name: String var description: String var price: Double var stock: Int init(name: String, description: String, price: Double, stock: Int) { self.name = name self.description =

爬取当当网的图书信息之封装一个工具类

把这个类名取为Tool 封装一个下载网页的方法GetHtml public static string GetHtml(string url) { try { WebClient wb = new WebClient(); return wb.DownloadString(url); } catch { return ""; } } 传入的是这个网页的URL,这个方法能帮我们把网页下载下来封装一个匹配图书类URL的的方法 public static ArrayList GetList(

封装一个工具类实现JDBC与MySQL数据库的连接

package com.cn.jdbc; import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.sql.Statement; public class JDBC_Connection { //加载驱动,链接数据库 public stati

【开源】1句代码搞定图片批量上传,无需什么代码功底【无语言界限】

开源地址:https://github.com/dunitian/LoTUploader WebUploader基础上的封装改善,一句代码全部实现(样式美化,实例JS优化(配置优化,样式调整,名称+大小显示,错误处理等),后端代码.....) 效果:(完整demo:https://github.com/dunitian/LoTUploader/tree/V1.0/Demo) 一句代码:$.lotuploader('lot-uploader', '/Home/Upload'); //必填参数:ID

封装JDBC工具类

JDBC连接数据库基本的步骤是固定的,这样就可以考虑封装一个工具类来简化数据库操作. 封装时用到了Java中的properties配置文件,是以一种键值对的形式存在的,可以把连接数据库要动态的信息保存到里面,这样比较直观,不容易出错,而且容易维护. 把配置文件放到src下就可以,如果要放到包下面就配置文件的相对路径就必须从包名开始. Demo : db.properties mysqlDriver=com.mysql.jdbc.Driver mysqlURL=jdbc:mysql://local

封装一个类搞定90%安卓客户端与服务器端交互

本实例封装了一个处理安卓客户端与服务器端交互的几个方法,对于中文乱码问题本实例也找到了解决方案.本例可以处理的场景如下: 1.与服务器端交互json数据. 2.Get方式与服务器端交互数据. 3.Post方式与服务器端交互数据. 4.HttpClient方式与服务器端交互数据. 5.上传文件到服务器端. 6.从服务器端下载文件. 7.从服务器端读取文本文件. 实例截图: 本篇文章将实例代码完整贴出,希望以本文作为一个交流的平台,大家集思广益封装出更好的处理类.交流地址: http://blog.

DAO设计模式实现数据库的增删改查(进一步封装JDBC工具类)

一.DAO模式简介 DAO即Data Access Object,数据访问接口.数据访问:故名思义就是与数据库打交道.夹在业务逻辑与数据库资源中间. DAO模式实际上是两个模式的组合,即Data Accessor (数据访问者)模式和 Active Domain Object(领域对象)模式.Data Accessor 模式实现了数据访问和业务逻辑的分离:Active Domain Object 模式实现了业务数据的对象化封装. 需要注意的是,DAO设计模式是Java EE中的设计模式,而非Ja

自己动手写工具:百度图片批量下载器

开篇:在某些场景下,我们想要对百度图片搜出来的东东进行保存,但是一个一个得下载保存不仅耗时而且费劲,有木有一种方法能够简化我们的工作量呢,让我们在离线模式下也能爽爽地浏览大量的美图呢?于是,我们想到了使用网络抓取去帮我们去下载图片,并且保存到我们设定的文件夹中,现在我们就来看看如何来设计开发一个这样的图片批量下载器. 一.关于网络抓取与爬虫 网络蜘蛛的主要作用是从Internet上不停地下载网络资源.它的基本实现思想就是通过一个或多个入口网址来获取更多的URL,然后通过对这些URL所指向的网络资