ImageDownLoader

FileUtils 类

public class FileUtils {
	/**
	 * sd卡的根目录
	 */
	private static String mSdRootPath = Environment.getExternalStorageDirectory().getPath();
	/**
	 * 手机的缓存根目录
	 */
	private static String mDataRootPath = null;
	/**
	 * 保存Image的目录名
	 */
	private final static String FOLDER_NAME = "/AndroidImage";
	
	
	public FileUtils(Context context){
		mDataRootPath = context.getCacheDir().getPath();
	}
	

	/**
	 * 获取储存Image的目录
	 * @return
	 */
	private String getStorageDirectory(){
		return Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED) ?
				mSdRootPath + FOLDER_NAME : mDataRootPath + FOLDER_NAME;
	}
	
	/**
	 * 保存Image的方法,有sd卡存储到sd卡,没有就存储到手机目录
	 * @param fileName 
	 * @param bitmap   
	 * @throws IOException
	 */
	public void savaBitmap(String fileName, Bitmap bitmap) throws IOException{
		if(bitmap == null){
			return;
		}
		String path = getStorageDirectory();
		File folderFile = new File(path);
		if(!folderFile.exists()){
			folderFile.mkdir();
		}
		File file = new File(path + File.separator + fileName);
		file.createNewFile();
		FileOutputStream fos = new FileOutputStream(file);
		bitmap.compress(CompressFormat.JPEG, 100, fos);
		fos.flush();
		fos.close();
	}
	
	/**
	 * 从手机或者sd卡获取Bitmap
	 * @param fileName
	 * @return
	 */
	public Bitmap getBitmap(String fileName){
		return BitmapFactory.decodeFile(getStorageDirectory() + File.separator + fileName);
	}
	
	/**
	 * 判断文件是否存在
	 * @param fileName
	 * @return
	 */
	public boolean isFileExists(String fileName){
		return new File(getStorageDirectory() + File.separator + fileName).exists();
	}
	
	/**
	 * 获取文件的大小
	 * @param fileName
	 * @return
	 */
	public long getFileSize(String fileName) {
		return new File(getStorageDirectory() + File.separator + fileName).length();
	}
	
	
	/**
	 * 删除SD卡或者手机的缓存图片和目录
	 */
	public void deleteFile() {
		File dirFile = new File(getStorageDirectory());
		if(! dirFile.exists()){
			return;
		}
		if (dirFile.isDirectory()) {
			String[] children = dirFile.list();
			for (int i = 0; i < children.length; i++) {
				new File(dirFile, children[i]).delete();
			}
		}
		
		dirFile.delete();
	}
}

ImageDownLoader 类

public class ImageDownLoader {
	/**
	 * 缓存Image的类,当存储Image的大小大于LruCache设定的值,系统自动释放内存
	 */
	private LruCache<String, Bitmap> mMemoryCache;
	/**
	 * 操作文件相关类对象的引用
	 */
	private FileUtils fileUtils;
	/**
	 * 下载Image的线程池
	 */
	private ExecutorService mImageThreadPool = null;
	
	
	public ImageDownLoader(Context context){
		//获取系统分配给每个应用程序的最大内存,每个应用系统分配32M
		int maxMemory = (int) Runtime.getRuntime().maxMemory();  
        int mCacheSize = maxMemory / 8;
        //给LruCache分配1/8 4M
		mMemoryCache = new LruCache<String, Bitmap>(mCacheSize){

			//必须重写此方法,来测量Bitmap的大小
			@Override
			protected int sizeOf(String key, Bitmap value) {
				return value.getRowBytes() * value.getHeight();
			}
			
		};
		
		fileUtils = new FileUtils(context);
	}
	
	
	/**
	 * 获取线程池的方法,因为涉及到并发的问题,我们加上同步锁
	 * @return
	 */
	public ExecutorService getThreadPool(){
		if(mImageThreadPool == null){
			synchronized(ExecutorService.class){
				if(mImageThreadPool == null){
					//为了下载图片更加的流畅,我们用了2个线程来下载图片
					mImageThreadPool = Executors.newFixedThreadPool(2);
				}
			}
		}
		
		return mImageThreadPool;
		
	}
	
	/**
	 * 添加Bitmap到内存缓存
	 * @param key
	 * @param bitmap
	 */
	public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  
	    if (getBitmapFromMemCache(key) == null && bitmap != null) {  
	        mMemoryCache.put(key, bitmap);  
	    }  
	}  
	 
	/**
	 * 从内存缓存中获取一个Bitmap
	 * @param key
	 * @return
	 */
	public Bitmap getBitmapFromMemCache(String key) {  
	    return mMemoryCache.get(key);  
	} 
	
	/**
	 * 先从内存缓存中获取Bitmap,如果没有就从SD卡或者手机缓存中获取,SD卡或者手机缓存
	 * 没有就去下载
	 * @param url
	 * @param listener
	 * @return
	 */
	public Bitmap downloadImage(final String url, final onImageLoaderListener listener){
		//替换Url中非字母和非数字的字符,这里比较重要,因为我们用Url作为文件名,比如我们的Url
		//是Http://xiaanming/abc.jpg;用这个作为图片名称,系统会认为xiaanming为一个目录,
		//我们没有创建此目录保存文件就会报错
		final String subUrl = url.replaceAll("[^\\w]", "");
		Bitmap bitmap = showCacheBitmap(subUrl);
		if(bitmap != null){
			return bitmap;
		}else{
			
			final Handler handler = new Handler(){
				@Override
				public void handleMessage(Message msg) {
					super.handleMessage(msg);
					listener.onImageLoader((Bitmap)msg.obj, url);
				}
			};
			
			getThreadPool().execute(new Runnable() {
				
				@Override
				public void run() {
					Bitmap bitmap = getBitmapFormUrl(url);
					Message msg = handler.obtainMessage();
					msg.obj = bitmap;
					handler.sendMessage(msg);
					
					try {
						//保存在SD卡或者手机目录
						fileUtils.savaBitmap(subUrl, bitmap);
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					//将Bitmap 加入内存缓存
					addBitmapToMemoryCache(subUrl, bitmap);
				}
			});
		}
		
		return null;
	}
	
	/**
	 * 获取Bitmap, 内存中没有就去手机或者sd卡中获取,这一步在getView中会调用,比较关键的一步
	 * @param url
	 * @return
	 */
	public Bitmap showCacheBitmap(String url){
		if(getBitmapFromMemCache(url) != null){
			return getBitmapFromMemCache(url);
		}else if(fileUtils.isFileExists(url) && fileUtils.getFileSize(url) != 0){
			//从SD卡获取手机里面获取Bitmap
			Bitmap bitmap = fileUtils.getBitmap(url);
			
			//将Bitmap 加入内存缓存
			addBitmapToMemoryCache(url, bitmap);
			return bitmap;
		}
		
		return null;
	}
	
	
	/**
	 * 从Url中获取Bitmap
	 * @param url
	 * @return
	 */
	private Bitmap getBitmapFormUrl(String url) {
		Bitmap bitmap = null;
		HttpURLConnection con = null;
		try {
			URL mImageUrl = new URL(url);
			con = (HttpURLConnection) mImageUrl.openConnection();
			con.setConnectTimeout(10 * 1000);
			con.setReadTimeout(10 * 1000);
			con.setDoInput(true);
			con.setDoOutput(true);
			bitmap = BitmapFactory.decodeStream(con.getInputStream());
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if (con != null) {
				con.disconnect();
			}
		}
		return bitmap;
	}
	
	/**
	 * 取消正在下载的任务
	 */
	public synchronized void cancelTask() {
		if(mImageThreadPool != null){
			mImageThreadPool.shutdownNow();
			mImageThreadPool = null;
		}
	}
	
	
	/**
	 * 异步下载图片的回调接口
	 * @author len
	 *
	 */
	public interface onImageLoaderListener{
		void onImageLoader(Bitmap bitmap, String url);
	}
	
}


转载于:https://my.oschina.net/oppo4545/blog/202012

浏览并下载网页上的图片。 Image Downloader不出售,并且将始终是免费,开源的,并且没有广告或任何形式的跟踪算法! 您可以在此处找到源代码:https://github.com/vdsabev/image-downloader Image Downloader =================如果您需要从网页批量下载图像,使用此扩展程序,您可以:-查看页面包含的图像以及链接到的图像-按宽度,高度和URL进行过滤; 支持通配符和正则表达式-(可选)仅显示链接中的图像-通过单击图像选择要下载的图像-使用专用按钮下载或在新标签页中打开单个图像-自定义图像的显示宽度,列,边框大小和颜色-隐藏过滤器,不需要的按钮和通知按下“下载”按钮时,所有选定的图像都将保存到Chrome的默认下载目录,或者如果指定子文件夹名称,则保存到其中的目录。 警告:如果尚未设置默认的下载目录,则必须手动选择每个图像的保存位置,这可能会打开许多​​弹出窗口。 不建议您尝试一次在没有默认下载目录的情况下一次下载太多图像。 已知问题===============此扩展程序无法始终提取单击照片时打开的全分辨率图像(例如,在Facebook相册中)。 那是因为页面没有直接链接到图像,而是使用了脚本。 如果您需要那种功能,那么即使您无法大量下载图像,也可以使用诸如Hover Zoom的其他扩展。 更改日志=============== 2.4.2:-Chrome不允许访问跨域CSS规则的解决方法2.4.1:-修复了无效URL会破坏扩展名的问题- https://github.com/vdsabev/image-downloader/issues/23-将Zepto.js更新为1.2.0 2.4:-添加了在下载2.3前重命名文件的选项:-添加了对BMP,SVG和WebP图像的支持-增加了对相对URL的支持-通过搜索更少的元素提高了弹出窗口的加载速度-用chrome.runtime 2.2代替了不推荐使用的chrome.extension调用:-删除了访问标签的不必要权限-删除了由于提示而导致的捐赠提示一些用户认为它在第一次出现后并没有消失; 现在,将在首次安装时打开选项页-保存URL过滤器的值-修复某些尺寸调整问题的另一种尝试2.1:-添加了图像宽度/高度过滤器-由于某些原因,一次性重置了所有设置遇到尺寸问题的人-删除了按URL排序选项2.0:-添加了将文件保存到子文件夹的功能-利用Google Chrome下载API-实施了基于网格的更简洁设计-单击图像URL文本框现在将自动选择文本以便用户可以复制文本-修复了一些小的显示问题-添加了列数设置,删除了边框样式设置-选项页1.3中添加了捐赠按钮:-现在,样式标签中使用的图像也将包含在列表的末尾。 仅包含来自元素的内联样式属性的图像。 -新增了对数据URI的支持-若干错误修复和优化1.2:-更改了要显示在只读文本框中的图像上方的URL-将图像复选框移至顶部,并在每个图像复选框下方添加了打开和下载按钮-最初禁用了“下载”按钮和“所有”复选框-引入了一些新选项来隐藏过滤器,按钮和通知-删除了正文宽度选项; 弹出窗口的宽度现在相对于最大图像宽度选项重新调整大小-简化了设计1.1:-修复了最小和最大图像宽度的保存-在图像本身上方添加了URL以及用于切换的选项-添加了通配符过滤器模式(沿正常和正则表达式)-现在将保存所选过滤器的状态-将“按URL排序”选项移回过滤器-在选项页面中添加了“清除数据”按钮。 尽管该扩展程序尚未使用大量本地存储,但有人可能会喜欢此选项。 -重构了大量代码,尤其是本地存储1.0.13的使用:-添加了一条通知,使用户知道下载已开始-添加了一些动画并进一步完善了选项通知-修复了一些正在处理的事件处理程序多次附加1.0.12:-迁移到jQuery-为“所有”复选框实现了不确定的状态-如果未选中任何图像,则将禁用“下载”按钮-修复了带有重置选项的错误-现在用户可以选择保存重置值或只是通过重新加载页面来取消重置-就像通知1.0.11中所述:-更改了下载机制以支持Chrome v21 +-添加了“仅显示链接的图像”过滤器选项,当您只想下载页面上URL中的图像。 1.0.10:-添加了下载确认1.0.9:-图片数量现在将显示在“所有”复选框1.0.8旁:-添加了对锚定标记中的图片URL的检测; 请注意,此功能将不会检测不具有.jpg,.jpeg,.gif或.png文件扩展名的URL-它依赖于正则表达式,以避免可能向外部服务器发送1.0.7的数百个请求:-已删除当您按下“下载”时弹出的桌面通知系统,显示的文字描述应该易于控制(通过“选项”)并且不易受到干扰; 这也需要较少的扩展权限-添加了隐藏下载通知的选项; 大
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值