import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Log; import java.io.*; import java.util.*; public final class BitMapUtil { private static final Size ZERO_SIZE = new Size(0, 0); private static final BitmapFactory.Options OPTIONS_GET_SIZE = new BitmapFactory.Options(); private static final BitmapFactory.Options OPTIONS_DECODE = new BitmapFactory.Options(); private static final byte[] LOCKED = new byte[0]; // 此对象用来保持Bitmap的回收顺序,保证最后使用的图片被回收 private static final LinkedList<String> CACHE_ENTRIES = new LinkedList<String>(); // 线程请求创建图片的队列 private static final Queue<QueueEntry> TASK_QUEUE = new LinkedList<QueueEntry>(); // 保存队列中正在处理的图片的key,有效防止重复添加到请求创建队列 private static final Set TASK_QUEUE_INDEX = new HashSet(); // 缓存Bitmap // 通过图片路径,图片大小 private static final Map<String, Bitmap> IMG_CACHE_INDEX = new HashMap<String, Bitmap>(); 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 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; } }
相关推荐
System.OutOfMemoryException(解决方案).md
JPEGKIT的出现主要是为了解决Android应用在处理大量或大尺寸JPEG图片时可能出现的内存溢出问题。它通过将LIJPEG Turbo C库桥接到Android环境中,实现了对JPEG图像的底层优化处理。LIJPEG Turbo是一个著名的、高效的...
标题中的“SQL Server出现System.OutOfMemoryException异常的解决方法”指的是在使用SQL Server时遇到的一种常见错误,即系统内存不足异常(System.OutOfMemoryException)。这种异常通常发生在SQL Server试图处理的...
在什么情况下会出现OutOfMemonryException呢? 在我们试图新建一个对象时,而垃圾收集器又找不到任何可用内存时被抛出,这种情况下我们是可以捕获该 异常的; 另一种情况是,CLR需要内存时,而却系统却不能提供,也会抛出...
Java 内存泄露 解决方案 outofmemoryException 从实践获取真理
OOM(OutOfMemoryException)是 Android 应用程序中一种常见的异常,发生 OOM 的原因是程序需要申请一段“大”内存,但是虚拟机没有办法及时地给到,即使做了 GC 操作以后。为了减少单个 APP 对整个系统的影响,...
#### 三、Android中OOM与图片三级缓存的关系 **图片三级缓存与OOM关系**: - 图片三级缓存是为了提高图片加载速度而设计的,包括内存缓存、磁盘缓存和网络缓存。虽然它有助于加快图片显示速度,但如果内存缓存占用...
在.NET框架中,C#应用程序在执行过程...通过谨慎地创建和使用线程,可以避免不必要的内存压力,从而预防`OutOfMemoryException`的出现。在实际项目中,应结合具体场景,灵活应用这些知识,确保应用程序的稳定性和性能。
如果输入流中没有这些终止符,readLine()会不断读取并扩大输入缓冲区,直至耗尽所有堆内存,导致`OutOfMemoryException`,进而使Java虚拟机(JVM)和应用程序崩溃,形成拒绝服务(Denial of Service, DoS)攻击。...
在提供的压缩包文件中,`AddWaterMark.sln`是Visual Studio的解决方案文件,包含了项目的完整结构。`AddWaterMark`可能是一个项目文件或源代码文件,里面应该包含了使用Spire.Pdf库尝试添加水印的具体代码。通过查看...
8. **异常处理**:为了提高程序的健壮性,我们需要添加适当的异常处理代码,如尝试加载图片时可能出现的FileNotFoundException或OutOfMemoryException。 9. **资源管理**:在程序运行过程中,确保正确释放占用的...
1.StackOverFlowException (一般来说这个不是真的堆栈不够了,而是你的代码出现了无线递归),如果你用throw new StackOverFlowException 还是可以catch的2.OutOfMemoryException (好像只有 box newarr newobj 才会抛...
#### 解决方案 为了解决上述问题,可以采用`HttpWebRequest`结合分段上传的方式来优化大文件上传流程。这种方法的核心思想是将文件分成多个较小的数据块,逐一发送到服务器,从而降低单次内存占用量。以下是具体的...
#### 解决方案 ##### 使用HttpWebRequest实现分段上传 - **创建HttpWebRequest对象**:首先,需要创建一个`HttpWebRequest`对象,并设置必要的属性,比如请求方法(通常是POST)、请求头等。 - **分段读取文件**:...
在 Hibernate 中,如果我们需要批量处理大量数据,例如插入 1000 000 条记录,就会出现 OutOfMemoryException 异常。这是因为 Hibernate 的 Session 有一个一级缓存,会将所有对象存储在内存中。如果不及时清空缓存...
C# 中的错误处理是编程中不可或缺的一部分,它能够帮助开发者检测和解决程序中的错误。在 C# 中,错误处理是通过 try-catch 块来实现的,try 块中包含可能出现错误的代码,而 catch 块中包含错误处理代码。 在 C# ...