Android开发之一种简单的异步加载图片方法

首先说明的是,该方法已经被我抛弃了。之前用它,发现加载速度不好。具体没怎么细心的看。

现在我用volley了。拿出来只是给大家批判的。

package com.souya.seller.util.ex;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import AXLib.Utility.Console;
import AXLib.Utility.HttpClient;
import AXLib.Utility.Queue;
import AXLib.Utility.RuntimeExceptionEx;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore.Video.Thumbnails;
import android.util.Log;
import android.widget.ImageView;

import com.souya.seller.app.SellerApplication;

public class AsyncImageLoader {
	private static boolean _D =  false;//AppConfig._D &&
	private static final String TAG = "AsyncImageLoader";
	public static String CachePath = null;
	private static String ThumbnailPath = null;
	private static boolean _isInit = false;
	private static Context _ctx;
	private static Bitmap _empty = Bitmap.createBitmap(1, 1, Bitmap.Config.RGB_565);
	private static HashMap<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
	private static Queue<Runnable> queue = new Queue<Runnable>();
	// 线程池:最大50条,每次执行:1条,空闲线程结束的超时时间:180秒
	private static ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 20, 300, TimeUnit.SECONDS, queue);
	public final static AsyncImageLoader Instance = new AsyncImageLoader();

	public static void Init(final Context context) {
		CachePath = SellerApplication.getInstance().mAppCacheDir + "";
		ThumbnailPath = CachePath + "/thumbnails";
		if (!new File(ThumbnailPath).exists())
			new File(ThumbnailPath).mkdirs();
		_ctx = context;
		_isInit = true;
	}

	public static Drawable loadDrawable(final Context context, final String url, final ImageCallback imageCallback) {
		if (!_isInit)
			Init(context);
		final String key = url;
		synchronized (imageCache) {
			if (imageCache.containsKey(key)) {
				SoftReference<Bitmap> softReference = imageCache.get(key);
				Bitmap bmp = softReference.get();
				if (bmp != null && !bmp.isRecycled()) {
					if (bmp == _empty) {
						bmp = bmp;
					} else
						return new BitmapDrawable(bmp);
				}
			} else {
				imageCache.put(key, new SoftReference<Bitmap>(_empty));
			}
		}

		final Handler handler = new Handler() {
			public void handleMessage(Message message) {
				imageCallback.imageLoaded((Drawable) message.obj, url);
			}
		};

		// 用线程池来做下载图片的任务
		executor.execute(new Runnable() {
			@Override
			public void run() {
				Bitmap bmp = loadImage(url);
				if (bmp != null) {
					synchronized (imageCache) {
						if (imageCache.containsKey(key)) {
							imageCache.put(key, new SoftReference<Bitmap>(bmp));
							Message message = handler.obtainMessage(0, new BitmapDrawable(bmp));
							handler.sendMessage(message);
						} else {
							if (!bmp.isRecycled())
								bmp.recycle();
							bmp = null;
							System.gc();
						}
					}
				}
			}
		});
		return null;
	}

	public static Drawable loadDrawable(final Context context, final String url, final int width, final int height, final ImageCallback imageCallback) {
		if (!_isInit)
			Init(context);
		final String key = String.format("%s_%d_%d", url, width, height);
		if (imageCache.containsKey(key)) {
			SoftReference<Bitmap> softReference = imageCache.get(key);
			Bitmap bmp = softReference.get();
			if (bmp != null && !bmp.isRecycled()) {
				if (bmp == _empty) {
					bmp = bmp;
				} else
					return new BitmapDrawable(bmp);
			}

		} else {
			imageCache.put(key, new SoftReference<Bitmap>(_empty));
		}

		final Handler handler = new Handler() {
			public void handleMessage(Message message) {
				imageCallback.imageLoaded((Drawable) message.obj, url);
			}
		};

		// 用线程池来做下载图片的任务
		executor.execute(new Runnable() {
			@Override
			public void run() {
				Bitmap bmp = loadImageAndScale(url, width, height);
				if (imageCache.containsKey(key)) {
					imageCache.put(key, new SoftReference<Bitmap>(bmp));
					Message message = handler.obtainMessage(0, new BitmapDrawable(bmp));
					handler.sendMessage(message);
				} else {
					if (!bmp.isRecycled())
						bmp.recycle();
					bmp = null;
					System.gc();
				}
			}
		});

		return null;
	}

	public static void releaseDrawable(String url, int width, int height) {
		log("releaseDrawable" + url);
		String key = String.format("%s_%d_%d", url, width, height);
		releaseDrawable(key);

	}

	public static void releaseDrawable(String url) {
		try {
			log("releaseDrawable" + url);
			String key = url;
			synchronized (imageCache) {
				if (imageCache.containsKey(key)) {
					SoftReference<Bitmap> softReference = imageCache.get(key);
					imageCache.remove(key);
					Bitmap bmp = softReference.get();
					if (bmp != null && bmp != _empty && !bmp.isRecycled()) {
						bmp.recycle();
						bmp = null;
					}
					System.gc();
				}
			}
		} catch (Exception e) {
			String stack = RuntimeExceptionEx.GetStackTraceString(e);

		}
	}

	private static HashMap<String, Object> _loadImageLocks = new HashMap<String, Object>();

	public static Bitmap loadImage(String url) {
		log("londImage:" + url);
		Object lockObj = null;
		synchronized (_loadImageLocks) {
			if (_loadImageLocks.containsKey(url))
				lockObj = _loadImageLocks.get(url);
			else {
				lockObj = new Object();
				_loadImageLocks.put(url, lockObj);
			}
		}
		synchronized (lockObj) {
			if (isLocalImage(url))
				return loadLocalImage(url);
			else {
				String localUrl = getCacheFileName(url);
				Bitmap bmp = null;
				if (new File(localUrl).exists())
					bmp = loadLocalImage(localUrl);
				try {
					if (bmp == null)
						bmp = loadHttpImage(url, 0, 0);
				} catch (Throwable e) {
					if (_D)
						throw RuntimeExceptionEx.Create(e);
				}
				return bmp;
			}
		}

	}

	public static Bitmap loadImage(String url, int width, int height) {
		log("londImage:" + url);
		Object lockObj = null;
		synchronized (_loadImageLocks) {
			if (_loadImageLocks.containsKey(url))
				lockObj = _loadImageLocks.get(url);
			else {
				lockObj = new Object();
				_loadImageLocks.put(url, lockObj);
			}
		}
		synchronized (lockObj) {
			if (isLocalImage(url))
				return loadLocalImage(url, width, height);
			else {
				String localUrl = getCacheFileName(url);
				Bitmap bmp = null;
				if (new File(localUrl).exists())
					bmp = loadLocalImage(localUrl, width, height);
				try {
					if (bmp == null)
						bmp = loadHttpImage(url, width, height);
				} catch (Throwable e) {
					if (_D)
						throw RuntimeExceptionEx.Create(e);
				}
				return bmp;
			}
		}

	}

	private static Bitmap loadLocalImageByVideo(String url) {
		log("loadLocalImageByVideo:" + url);
		if (!new File(url).exists())
			return null;
		Bitmap bmp = ThumbnailUtils.createVideoThumbnail(url, Thumbnails.MINI_KIND);
		return bmp;
	}

	private static Bitmap loadLocalImage(String url) {
		return loadLocalImage(url, 0);
	}

	private static Bitmap loadLocalImage(String url, int width, int height) {
		if (width == 0 && height == 0)
			return loadLocalImage(url);
		else
			return _loadLocalImage(url, width, height);
	}

	private static Bitmap _loadLocalImage(String url, int width, int height) {
		try {

			if (!new File(url).exists())
				return null;

			// 获取屏幕的宽和高
			/**
			 * 为了计算缩放的比例,我们需要获取整个图片的尺寸,而不是图片
			 * BitmapFactory.Options类中有一个布尔型变量inJustDecodeBounds,将其设置为true
			 * 这样,我们获取到的就是图片的尺寸,而不用加载图片了。 当我们设置这个值的时候,我们接着就可以从BitmapFactory.
			 * Options的outWidth和outHeight中获取到值
			 */
			BitmapFactory.Options op = new BitmapFactory.Options();
			op.inJustDecodeBounds = true;

			Uri uri = Uri.fromFile(new File(url));

			// 由于使用了MediaStore存储,这里根据URI获取输入流的形式
			Bitmap pic = BitmapFactory.decodeStream(_ctx.getContentResolver().openInputStream(uri), null, op);

			int wRatio = (int) Math.ceil(op.outWidth / (float) width); // 计算宽度比例
			int hRatio = (int) Math.ceil(op.outHeight / (float) height); // 计算高度比例
			if (pic != null && !pic.isRecycled())
				pic.recycle();
			/**
			 * 接下来,我们就需要判断是否需要缩放以及到底对宽还是高进行缩放。 如果高和宽不是全都超出了屏幕,那么无需缩放。
			 * 如果高和宽都超出了屏幕大小,则如何选择缩放呢》 这需要判断wRatio和hRatio的大小
			 * 大的一个将被缩放,因为缩放大的时,小的应该自动进行同比率缩放。 缩放使用的还是inSampleSize变量
			 */
			if (wRatio > 1 && hRatio > 1) {
				if (wRatio > hRatio) {
					op.inSampleSize = wRatio;
				} else {
					op.inSampleSize = hRatio;
				}
			}
			op.inJustDecodeBounds = false; // 注意这里,一定要设置为false,因为上面我们将其设置为true来获取图片尺寸了
			try {
				pic = BitmapFactory.decodeStream(_ctx.getContentResolver().openInputStream(uri), null, op);
			} catch (OutOfMemoryError e) {
				loadLocalImage(url, 1);
			}
			return pic;
		} catch (Throwable e) {
			throw RuntimeExceptionEx.Create(e);
		}
	}

	private static Bitmap loadLocalImage(String url, int inSampleSize) {
		log("loadLocalImage:" + url);
		if (!new File(url).exists())
			return null;
		if (url.endsWith(".mp4") || url.endsWith(".3gp")) {
			return loadLocalImageByVideo(url);
		}
		BitmapFactory.Options opt = new BitmapFactory.Options();
		// opt.inPreferredConfig = Bitmap.Config.RGB_565;
		// opt.inPurgeable = true;
		// opt.inInputShareable = true;
		opt.inSampleSize = inSampleSize;
		// 获取资源图片
		InputStream is = null;
		try {
			is = new FileInputStream(url);
			if (is != null) {

				Bitmap map = BitmapFactory.decodeStream(is, null, opt);
				if (map == null)
					return null;
				int height = map.getHeight();
				int width = map.getWidth();

				if (width > 1920 || height > 1080) {
					if (inSampleSize == 0)
						inSampleSize = 2;
					else
						inSampleSize++;
					if (is != null) {
						try {
							is.close();
						} catch (Exception ex) {

						}
					}
					map.recycle();
					map = null;
					return loadLocalImage(url, inSampleSize);
				} else {
					return map;
				}
			}
		} catch (OutOfMemoryError e) {
			if (is != null) {
				try {
					is.close();
				} catch (Exception ex) {

				}
			}
			System.gc();
			if (inSampleSize < 50) {
				if (inSampleSize == 0)
					inSampleSize = 2;
				else
					inSampleSize++;
				return loadLocalImage(url, inSampleSize);
			} else
				return null;

		} catch (Throwable e) {
			String stack = RuntimeExceptionEx.GetStackTraceString(e);
			//CLLog.Error(e);
			//if (_D)
		    //	throw RuntimeExceptionEx.Create(e);
		} finally {
			if (is != null) {
				try {
					is.close();
				} catch (Exception e) {

				}
			}
			System.gc();

		}
		return null;
	}

	private static Bitmap loadHttpImage(String url, int width, int height) {
		log("loadHttpImage:" + url);
		String localUrl = getCacheFileName(url);
		try {
			HttpClient hc = new HttpClient();
			if (hc.downFile(url, localUrl))
				return loadLocalImage(localUrl, width, height);
			else
				return null;
		} catch (Exception e) {
			String stack = RuntimeExceptionEx.GetStackTraceString(e);
			//CLLog.Error(e);
			//if (_D)
			//	throw RuntimeExceptionEx.Create(e);
		}

		return null;
	}

	public static Bitmap loadImageAndScale(String url, int width, int height) {
		log("loadImageAndScale:" + url);
		String thumbnailUrl = getThumbnailFileName(url, width, height);
		Bitmap bmp = loadLocalImage(url, width, height);
		if (bmp == null) {
			try {
				bmp = loadImage(url, width, height);
			} catch (Exception e) {
				String stack = RuntimeExceptionEx.GetStackTraceString(e);
			}
			if (bmp != null) {
				Bitmap bmpThumbnail = ImageHelper.ScaleAndSave(bmp, thumbnailUrl, width, height, true, true);
				if (bmpThumbnail != bmp && !bmp.isRecycled())
					bmp.recycle();
				bmp = null;
				System.gc();
				bmp = bmpThumbnail;
			}
		}
		return bmp;
	}

	private static boolean isLocalImage(String url) {
		return new File(url).exists();
	}

	private static String getCacheFileName(String url) {
		if (isLocalImage(url))
			return url;
		String localUrl = null;
		if (url != null && url.length() != 0) {
			localUrl = CachePath + "/" + url.substring(url.lastIndexOf("/") + 1);
		}
		return localUrl;
	}

	private static String getThumbnailFileName(String url, int width, int height) {
		String thumbnailUrl = null;
		if (url != null && url.length() != 0) {
			thumbnailUrl = String.format("%s/%d_%d_%s", ThumbnailPath, width, height, url.substring(url.lastIndexOf("/") + 1));
		}
		return thumbnailUrl;
	}

	private static void log(String msg) {
		// Console.d("AsyncImageLoader", msg);
	}

	public interface ImageCallback {
		public void imageLoaded(Drawable imageDrawable, String imageUrl);
	}

}
时间: 2024-11-08 18:47:01

Android开发之一种简单的异步加载图片方法的相关文章

android开发干货:实现listview异步加载图片

针对listview异步加载图片这个问题,麦子学院android开发老师讲了一种非常实用的方法,麦子学院android开发老师说凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.

Android进阶:ListView性能优化异步加载图片 使滑动效果流畅

ListView 是一种可以显示一系列项目并能进行滚动显示的 View,每一行的Item可能包含复杂的结构,可能会从网络上获取icon等的一些图标信息,就现在的网络速度要想保持ListView运行的很好滚动流畅是做不到的 所以这里就需要把这些信息利用多线程实现异步加载 实现这样功能的类 [java] view plaincopy public class AsyncImageLoader { private HashMap<String, SoftReference<Drawable>&

LruCache缓存处理及异步加载图片类的封装

Android中的缓存处理及异步加载图片类的封装 一.缓存介绍: (一).Android中缓存的必要性: 智能手机的缓存管理应用非常的普遍和需要,是提高用户体验的有效手段之一. 1.没有缓存的弊端: 流量开销:对于客户端——服务器端应用,从远程获取图片算是经常要用的一个功能,而图片资源往往会消耗比较大的流量. 加载速度:如果应用中图片加载速度很慢的话,那么用户体验会非常糟糕. 那么如何处理好图片资源的获取和管理呢?异步下载+本地缓存 2.缓存带来的好处: 1. 服务器的压力大大减小: 2. 客户

Android 异步加载图片,使用LruCache和SD卡或手机缓存,效果非常的流畅

转载请注明出处http://blog.csdn.net/xiaanming/article/details/9825113 异步加载图片的例子,网上也比较多,大部分用了HashMap<String, SoftReference<Drawable>> imageCache ,但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠.另外,Android 3.0

android listview 异步加载图片并防止错位

网上找了一张图, listview 异步加载图片之所以错位的根本原因是重用了 convertView 且有异步操作. 如果不重用 convertView 不会出现错位现象, 重用 convertView 但没有异步操作也不会有问题. 我简单分析一下: 当重用 convertView 时,最初一屏显示 7 条记录, getView 被调用 7 次,创建了 7 个 convertView. 当 Item1 划出屏幕, Item8 进入屏幕时,这时没有为 Item8 创建新的 view 实例, Ite

Android ListView异步加载图片乱序问题,原因分析及解决方案

转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/45586553 在Android所有系统自带的控件当中,ListView这个控件算是用法比较复杂的了,关键是用法复杂也就算了,它还经常会出现一些稀奇古怪的问题,让人非常头疼.比如说在ListView中加载图片,如果是同步加载图片倒还好,但是一旦使用异步加载图片那么问题就来了,这个问题我相信很多Android开发者都曾经遇到过,就是异步加载图片会出现错位乱序的情况.遇到这个问题时,不

android实用技巧:android实现listview异步加载图片

针对listview异步加载图片这个问题,麦子学院android开发老师讲了一种非常实用的方法,麦子学院android开发老师说凡是是要通过网络获取图片资源一般使用这种方法比较好,用户体验好,下面就说实现方法,先贴上主方法的代码: package cn.wangmeng.test; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.

Android中ListView异步加载图片错位、重复、闪烁问题分析及解决方案

Android中ListView异步加载图片错位.重复.闪烁问题分析及解决方案 我们在使用ListView异步加载图片的时候,在快速滑动或者网络不好的情况下,会出现图片错位.重复.闪烁等问题,其实这些问题总结起来就是一个问题,我们需要对这些问题进行ListView的优化. 比如ListView上有100个Item,一屏只显示10个Item,我们知道getView()中convertView是用来复用View对象的,因为一个Item的对应一个View对象,而ImageView控件就是View对象通

Android:ViewPager扩展详解——带有导航的ViewPagerIndicator(附带图片缓存,异步加载图片)

大家都用过viewpager了, github上有对viewpager进行扩展,导航风格更加丰富,这个开源项目是ViewPagerIndicator,很好用,但是例子比较简单,实际用起来要进行很多扩展,比如在fragment里进行图片缓存和图片异步加载. 下面是ViewPagerIndicator源码运行后的效果,大家也都看过了,我多此一举截几张图: 下载源码请点击这里 ===========================================华丽的分割线==============