`

Andorid读取本地图片出现OutOfMemoryException解决方案

阅读更多
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

    System.OutOfMemoryException(解决方案).md

    jpegkit-android,Android的高效JPEG操作,无OutOfMemoryException风险。.zip

    JPEGKIT的出现主要是为了解决Android应用在处理大量或大尺寸JPEG图片时可能出现的内存溢出问题。它通过将LIJPEG Turbo C库桥接到Android环境中,实现了对JPEG图像的底层优化处理。LIJPEG Turbo是一个著名的、高效的...

    SQL Server出现System.OutOfMemoryException异常的解决方法

    标题中的“SQL Server出现System.OutOfMemoryException异常的解决方法”指的是在使用SQL Server时遇到的一种常见错误,即系统内存不足异常(System.OutOfMemoryException)。这种异常通常发生在SQL Server试图处理的...

    Net 内存溢出(System.OutOfMemoryException)的常见情况和处理方式总结

    在什么情况下会出现OutOfMemonryException呢? 在我们试图新建一个对象时,而垃圾收集器又找不到任何可用内存时被抛出,这种情况下我们是可以捕获该 异常的; 另一种情况是,CLR需要内存时,而却系统却不能提供,也会抛出...

    Java内存泄露解决方案

    Java 内存泄露 解决方案 outofmemoryException 从实践获取真理

    android framework面试题集

    OOM(OutOfMemoryException)是 Android 应用程序中一种常见的异常,发生 OOM 的原因是程序需要申请一段“大”内存,但是虚拟机没有办法及时地给到,即使做了 GC 操作以后。为了减少单个 APP 对整个系统的影响,...

    Android基础面试笔记

    #### 三、Android中OOM与图片三级缓存的关系 **图片三级缓存与OOM关系**: - 图片三级缓存是为了提高图片加载速度而设计的,包括内存缓存、磁盘缓存和网络缓存。虽然它有助于加快图片显示速度,但如果内存缓存占用...

    dotnet C# 应用程序进程创建太多线程将会抛出 OutOfMemoryException 异常.rar

    在.NET框架中,C#应用程序在执行过程...通过谨慎地创建和使用线程,可以避免不必要的内存压力,从而预防`OutOfMemoryException`的出现。在实际项目中,应结合具体场景,灵活应用这些知识,确保应用程序的稳定性和性能。

    AppScan Source测试ExploitMe Mobile Android Labs项目.docx

    如果输入流中没有这些终止符,readLine()会不断读取并扩大输入缓冲区,直至耗尽所有堆内存,导致`OutOfMemoryException`,进而使Java虚拟机(JVM)和应用程序崩溃,形成拒绝服务(Denial of Service, DoS)攻击。...

    给pdf加水印

    在提供的压缩包文件中,`AddWaterMark.sln`是Visual Studio的解决方案文件,包含了项目的完整结构。`AddWaterMark`可能是一个项目文件或源代码文件,里面应该包含了使用Spire.Pdf库尝试添加水印的具体代码。通过查看...

    简易的图片浏览器

    8. **异常处理**:为了提高程序的健壮性,我们需要添加适当的异常处理代码,如尝试加载图片时可能出现的FileNotFoundException或OutOfMemoryException。 9. **资源管理**:在程序运行过程中,确保正确释放占用的...

    .net 一些无法catch的异常

    1.StackOverFlowException (一般来说这个不是真的堆栈不够了,而是你的代码出现了无线递归),如果你用throw new StackOverFlowException 还是可以catch的2.OutOfMemoryException (好像只有 box newarr newobj 才会抛...

    使用HttpWebRequest实现大文件上传

    #### 解决方案 为了解决上述问题,可以采用`HttpWebRequest`结合分段上传的方式来优化大文件上传流程。这种方法的核心思想是将文件分成多个较小的数据块,逐一发送到服务器,从而降低单次内存占用量。以下是具体的...

    使用HttpWebRequest实现大文件上最新传

    #### 解决方案 ##### 使用HttpWebRequest实现分段上传 - **创建HttpWebRequest对象**:首先,需要创建一个`HttpWebRequest`对象,并设置必要的属性,比如请求方法(通常是POST)、请求头等。 - **分段读取文件**:...

    hibernate性能优化.doc

    在 Hibernate 中,如果我们需要批量处理大量数据,例如插入 1000 000 条记录,就会出现 OutOfMemoryException 异常。这是因为 Hibernate 的 Session 有一个一级缓存,会将所有对象存储在内存中。如果不及时清空缓存...

    c#常见错误处理的几种方法

    C# 中的错误处理是编程中不可或缺的一部分,它能够帮助开发者检测和解决程序中的错误。在 C# 中,错误处理是通过 try-catch 块来实现的,try 块中包含可能出现错误的代码,而 catch 块中包含错误处理代码。 在 C# ...

Global site tag (gtag.js) - Google Analytics