前些日子一直为图片内存溢出问题困扰着,查了N多资料,将google彻底翻遍了都没找到解决方案,就当我几乎绝望的时候意外发现了一位网友的一个 工具类,抱着最后一丝希望将代码co过来试了一把,结果令我喜出望外。嘿,解决了!暂不说多么欢喜了,听我慢慢道来这其中的前因后果吧!
需求:下载时候将图片一并down下来,在空间里显示并支持离线观看
第一个版本代码:
//从本地读取图片
public Bitmap getBitmapFromSD(String filename) {
FileInputStream fi = null;
BufferedInputStream bi = null;
Bitmap bp = null;
try {
fi = new FileInputStream(filename);
bi = new BufferedInputStream(fi);
bp = BitmapFactory.decodeStream(bi);
} catch (IOException e) {
bp = null;
} finally {
try {
if (bi != null) {
bi.close();
}
if (fi != null) {
fi.close();
}
} catch (IOException e) {
bp = null;
}
}
return bp;
}
问题出现了,由于显示的图片过大,所以会出现OutOfMemoryException。我就设想能否捕捉异常来回收图片再重新加载,于是欲从网上找解决办法,什么手动干预GC,什么将图片弱化什么使用弱引用保存图片,有些总结得特别好(http://mzh3344258.blog.51cto.com/1823534/804237),这些方法我一一尝试可问题仍然未解决。不断的OOM,不断的尝试recycle,错误倒是不出现,可一旦内存吃不消就会显示不了图片,出现的都是默认图片。最终我从网上找到如下工具类,助我很好的解决了此问题,具体网址忘记了(得谢谢那位网友啦(*^__^*) ),现在代码贴出来以便下次顺手拈来
public final class BitMapUtil {
private static final Size ZERO_SIZE = new Size(0, 0);
private static final Options OPTIONS_GET_SIZE = new Options();
private static final Options OPTIONS_DECODE = new Options();
private static final byte[] LOCKED = new byte[0];
// 此对象用来保持Bitmap的回收顺序,保证最后使用的图片被回收
private static final LinkedList CACHE_ENTRIES = new LinkedList();
// 线程请求创建图片的队列
private static final Queue TASK_QUEUE = new LinkedList();
// 保存队列中正在处理的图片的key,有效防止重复添加到请求创建队列
private static final Set TASK_QUEUE_INDEX = new HashSet();
// 缓存Bitmap
private static final Map IMG_CACHE_INDEX = new HashMap(); // 通过图片路径,图片大小
private static int CACHE_SIZE = 20; // 缓存图片数量
static {
OPTIONS_GET_SIZE.inJustDecodeBounds = true;
// 初始化创建图片线程,并等待处理
new Thread() {
{
setDaemon(true);
}
public void run() {
while (true) {
synchronized (TASK_QUEUE) {
if (TASK_QUEUE.isEmpty()) {
try {
TASK_QUEUE.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
QueueEntry entry = TASK_QUEUE.poll();
String key = createKey(entry.path, entry.width,
entry.height);
TASK_QUEUE_INDEX.remove(key);
createBitmap(entry.path, entry.width, entry.height);
}
}
}.start();
}
public static Bitmap getBitmap(String path, int width, int height) {
if(path==null){
return null;
}
Bitmap bitMap = null;
try {
if (CACHE_ENTRIES.size() >= CACHE_SIZE) {
destoryLast();
}
bitMap = useBitmap(path, width, height);
if (bitMap != null && !bitMap.isRecycled()) {
return bitMap;
}
bitMap = createBitmap(path, width, height);
String key = createKey(path, width, height);
synchronized (LOCKED) {
IMG_CACHE_INDEX.put(key, bitMap);
CACHE_ENTRIES.addFirst(key);
}
} catch (OutOfMemoryError err) {
destoryLast();
System.out.println(CACHE_SIZE);
return createBitmap(path, width, height);
}
return bitMap;
}
public static Size getBitMapSize(String path) {
File file = new File(path);
if (file.exists()) {
InputStream in = null;
try {
in = new FileInputStream(file);
BitmapFactory.decodeStream(in, null, OPTIONS_GET_SIZE);
return new Size(OPTIONS_GET_SIZE.outWidth,
OPTIONS_GET_SIZE.outHeight);
} catch (FileNotFoundException e) {
return ZERO_SIZE;
} finally {
closeInputStream(in);
}
}
return ZERO_SIZE;
}
// ------------------------------------------------------------------ private Methods
// 将图片加入队列头
private static Bitmap useBitmap(String path, int width, int height) {
Bitmap bitMap = null;
String key = createKey(path, width, height);
synchronized (LOCKED) {
bitMap = IMG_CACHE_INDEX.get(key);
if (null != bitMap) {
if (CACHE_ENTRIES.remove(key)) {
CACHE_ENTRIES.addFirst(key);
}
}
}
return bitMap;
}
// 回收最后一张图片
private static void destoryLast() {
synchronized (LOCKED) {
String key = CACHE_ENTRIES.removeLast();
if (key.length() > 0) {
Bitmap bitMap = IMG_CACHE_INDEX.remove(key);
if (bitMap != null && !bitMap.isRecycled()) {
bitMap.recycle();
bitMap = null;
}
}
}
}
// 创建键
private static String createKey(String path, int width, int height) {
if (null == path || path.length() == 0) {
return "";
}
return path + "_" + width + "_" + height;
}
// 通过图片路径,宽度高度创建一个Bitmap对象
private static Bitmap createBitmap(String path, int width, int height) {
File file = new File(path);
if (file.exists()) {
InputStream in = null;
try {
in = new FileInputStream(file);
Size size = getBitMapSize(path);
if (size.equals(ZERO_SIZE)) {
return null;
}
int scale = 1;
int a = size.getWidth() / width;
int b = size.getHeight() / height;
scale = Math.max(a, b);
synchronized (OPTIONS_DECODE) {
OPTIONS_DECODE.inSampleSize = scale;
Bitmap bitMap = BitmapFactory.decodeStream(in, null,
OPTIONS_DECODE);
return bitMap;
}
} catch (FileNotFoundException e) {
Log.v("BitMapUtil","createBitmap=="+e.toString());
} finally {
closeInputStream(in);
}
}
return null;
}
// 关闭输入流
private static void closeInputStream(InputStream in) {
if (null != in) {
try {
in.close();
} catch (IOException e) {
Log.v("BitMapUtil","closeInputStream=="+e.toString());
}
}
}
// 图片大小
static class Size {
private int width, height;
Size(int width, int height) {
this.width = width;
this.height = height;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
}
// 队列缓存参数对象
static class QueueEntry {
public String path;
public int width;
public int height;
}
}
在使用时我只调用了getBitmap方法,将需要设置的高度宽度以及本地图片路径传递过去就能自动返回bitmap给我,而且当捕捉到OOMError 的时候将LinkedList的最后一张图片也就是最先存的图片进行溢出并回收就大功告成,特别注意的是这里捕捉错误Exception是获取不到的,一 定要手动捕获OutOfMemoryError你才能进行处理(估计这些道理大家都懂得,所以不赘述啦,童鞋们加油!办法总比困难多o(∩_∩)o )
相关推荐
JPEGKIT将LIJPEG Turbo C 库桥接到Android中,并用一个易于使用的类来封装它。您当前可以:
在什么情况下会出现OutOfMemonryException呢? 在我们试图新建一个对象时,而垃圾收集器又找不到任何可用内存时被抛出,这种情况下我们是可以捕获该 异常的; 另一种情况是,CLR需要内存时,而却系统却不能提供,也会抛出...
主要介绍了SQL Server出现System.OutOfMemoryException异常的解决方法,同时提供了微软官方的解决方案,需要的朋友可以参考下
使用Spire.Pdf添加水印,提示“System.OutOfMemoryException”异常和“未将对象引用设置到对象的实例”
1.StackOverFlowException (一般来说这个不是真的堆栈不够了,而是你的代码出现了无线递归),如果你用throw new StackOverFlowException 还是可以catch的2.OutOfMemoryException (好像只有 box newarr newobj 才会抛...
Java 内存泄露 解决方案 outofmemoryException 从实践获取真理
我们在开发过程中曾经遇到过一个奇怪的问题:当软件加载了很多比较大规模的数据后,会偶尔出现OutOfMemoryException异常,但通过内存检查工具却发现还有很多可用内存。于是我们怀疑是可用内存总量充足,但却没有足够...
产服务器宕机。从当时的日志情况来看请求操作失败,资源等待操作,,现实抛出内存溢出(OutOfMemoryException)异常
You can now double-click the appstart.jar and your application is started, without hideous DOS windows, class-path headhaches or fears of the dreaded OutOfMemoryException. ...
对于多线程,您需要考虑线程安全,并且它可能会意外崩溃(例如OutOfMemoryException)并且所有线程都中止。如果您使用 jvmpart 进行处理,则一个崩溃永远不会影响其他崩溃,所有 JVM 进程都是独立运行的,并且与它...
JanusGraph over HBase支持全局顶点和边缘...但是,请注意,所有这些顶点和/或边都将加载到内存中,这可能会导致OutOfMemoryException。使用JanusGraph和TinkerPop的Hadoop-Gremlin有效地遍历大型图中的所有顶点或边。
这种尝试的结果应该可以实现该存储实现的生产就绪使用,并处理内存处理的特定属性,例如不惜一切代价避免OutOfMemoryException并在垃圾回收上减轻负担。 当然,我们不能完全避免它们,但至少可以以某种方式控制它们...
需要从JVM OutOfMemoryException(OME)中恢复JVM具有-XX:OnOutOfMemoryError选项,该选项可让您在脚本因OME而死时运行。 这是如何使用它的一个例子。 startTest.sh启动一个Java程序,该Java程序在内存不足的情况下...
我无法帮助解决与“OutOfMemoryException”错误相关的任何事情。 我建议为每个工具使用提供的 powershell 脚本(.ps1 文件)(带有必要的个人编辑)。 默认情况下,脚本被设置为使用syncMode 0(同步),因此,...
7.3.7 OutOfMemoryException 187 7.3.8 ComException、SEHException及其他CLR异常 188 7.3.9 ExecutionEngineException 188 7.4 自定义异常的设计 188 7.5 异常与性能 190 7.5.1 Tester-Doer模式 190 ...
7.3.7 OutOfMemoryException 187 7.3.8 ComException、SEHException及其他CLR异常 188 7.3.9 ExecutionEngineException 188 7.4 自定义异常的设计 188 7.5 异常与性能 190 7.5.1 Tester-Doer模式 190 ...