android 加载图片轻松避免OOM(out of memory)

在使用android加载图片的时候,经常会出现内存溢出,主要是由于android可使用的内存太小,而通过代码加载进来的图片,并不会被GC回收,于是我写了一个工具类用来加载图片,并且建立缓存,轻松避免内存溢出,废话不多说,上代码

[java] view
plain
copy

  1. package l.test1.util;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.FileNotFoundException;  
  6. import java.io.IOException;  
  7. import java.io.InputStream;  
  8. import java.util.HashMap;  
  9. import java.util.HashSet;  
  10. import java.util.LinkedList;  
  11. import java.util.Map;  
  12. import java.util.Queue;  
  13. import java.util.Set;  
  14.   
  15. import android.graphics.Bitmap;  
  16. import android.graphics.BitmapFactory;  
  17. import android.graphics.BitmapFactory.Options;  
  18.   
  19. /** 
  20.  * Bitmap工具类,缓存用过的指定数量的图片,使用此工具类,不再需要手动管理Bitmap内存 原理: 
  21.  * 用一个队列保存使用Bitmap的顺序,每次使用Bitmap将对象移动到队列头 当内存不够,或者达到制定的缓存数量的时候,回收队列尾部图片 
  22.  * 保证当前使用最多的图片得到最长时间的缓存,提高速度 
  23.  *  
  24.  * @author liaoxingliao 
  25.  *  
  26.  */  
  27. public final class BitMapUtil {  
  28.   
  29.     private static final Size ZERO_SIZE = new Size(0, 0);  
  30.     private static final Options OPTIONS_GET_SIZE = new Options();  
  31.     private static final Options OPTIONS_DECODE = new Options();  
  32.     private static final byte[] LOCKED = new byte[0];  
  33.   
  34.     private static final LinkedList<String> CACHE_ENTRIES = new LinkedList<String>(); // 此对象用来保持Bitmap的回收顺序,保证最后使用的图片被回收  
  35.     private static final Queue<QueueEntry> TASK_QUEUE = new LinkedList<QueueEntry>(); // 线程请求创建图片的队列  
  36.     private static final Set<String> TASK_QUEUE_INDEX = new HashSet<String>(); // 保存队列中正在处理的图片的key,有效防止重复添加到请求创建队列  
  37.   
  38.     private static final Map<String, Bitmap> IMG_CACHE_INDEX = new HashMap<String, Bitmap>(); // 缓存Bitmap  
  39.                                                                                                 // 通过图片路径,图片大小  
  40.   
  41.     private static int CACHE_SIZE = 200; // 缓存图片数量  
  42.   
  43.     static {  
  44.         OPTIONS_GET_SIZE.inJustDecodeBounds = true;  
  45.         // 初始化创建图片线程,并等待处理  
  46.         new Thread() {  
  47.             {  
  48.                 setDaemon(true);  
  49.             }  
  50.   
  51.             public void run() {  
  52.                 while (true) {  
  53.                     synchronized (TASK_QUEUE) {  
  54.                         if (TASK_QUEUE.isEmpty()) {  
  55.                             try {  
  56.                                 TASK_QUEUE.wait();  
  57.                             } catch (InterruptedException e) {  
  58.                                 e.printStackTrace();  
  59.                             }  
  60.                         }  
  61.                     }  
  62.                     QueueEntry entry = TASK_QUEUE.poll();  
  63.                     String key = createKey(entry.path, entry.width,  
  64.                             entry.height);  
  65.                     TASK_QUEUE_INDEX.remove(key);  
  66.                     //createBitmap(entry.path, entry.width, entry.height);  
  67.                     //修正过的代码  
  68.                     getBitmap(entry.path,entry.width,entry.height);  
  69.                 }  
  70.             }  
  71.         }.start();  
  72.   
  73.     }  
  74.   
  75.     /** 
  76.      * 创建一张图片 如果缓存中已经存在,则返回缓存中的图,否则创建一个新的对象,并加入缓存 
  77.      * 宽度,高度,为了缩放原图减少内存的,如果输入的宽,高,比原图大,返回原图 
  78.      *  
  79.      * @param path      图片物理路径 (必须是本地路径,不能是网络路径) 
  80.      * @param width     需要的宽度 
  81.      * @param height    需要的高度 
  82.      * @return 
  83.      */  
  84.     public static Bitmap getBitmap(String path, int width, int height) {  
  85.         Bitmap bitMap = null;  
  86.         try {  
  87.             if (CACHE_ENTRIES.size() >= CACHE_SIZE) {  
  88.                 destoryLast();  
  89.             }  
  90.             bitMap = useBitmap(path, width, height);  
  91.             if (bitMap != null && !bitMap.isRecycled()) {  
  92.                 return bitMap;  
  93.             }  
  94.             bitMap = createBitmap(path, width, height);  
  95.             String key = createKey(path, width, height);  
  96.             synchronized (LOCKED) {  
  97.                 IMG_CACHE_INDEX.put(key, bitMap);  
  98.                 CACHE_ENTRIES.addFirst(key);  
  99.             }  
  100.         } catch (OutOfMemoryError err) {  
  101.             destoryLast();  
  102.             System.out.println(CACHE_SIZE);  
  103.             //return createBitmap(path, width, height);  
  104.             //修正过的代码  
  105.             return getBitmap(path, width, height);  
  106.         }  
  107.         return bitMap;  
  108.     }  
  109.   
  110.     /** 
  111.      * 设置缓存图片数量 如果输入负数,会产生异常 
  112.      *  
  113.      * @param size 
  114.      */  
  115.     public static void setCacheSize(int size) {  
  116.         if (size <= 0) {  
  117.             throw new RuntimeException("size :" + size);  
  118.         }  
  119.         while (size < CACHE_ENTRIES.size()) {  
  120.             destoryLast();  
  121.         }  
  122.         CACHE_SIZE = size;  
  123.     }  
  124.   
  125.     /** 
  126.      * 加入一个图片处理请求到图片创建队列 
  127.      *  
  128.      * @param path 
  129.      *            图片路径(本地) 
  130.      * @param width 
  131.      *            图片宽度 
  132.      * @param height 
  133.      *            图片高度 
  134.      */  
  135.     public static void addTask(String path, int width, int height) {  
  136.         QueueEntry entry = new QueueEntry();  
  137.         entry.path = path;  
  138.         entry.width = width;  
  139.         entry.height = height;  
  140.         synchronized (TASK_QUEUE) {  
  141.             String key = createKey(path, width, height);  
  142.             if (!TASK_QUEUE_INDEX.contains(key)  
  143.                     && !IMG_CACHE_INDEX.containsKey(key)) {  
  144.                 TASK_QUEUE.add(entry);  
  145.                 TASK_QUEUE_INDEX.add(key);  
  146.                 TASK_QUEUE.notify();  
  147.             }  
  148.         }  
  149.     }  
  150.       
  151.     /** 
  152.      * 通过图片路径返回图片实际大小 
  153.      * @param path      图片物理路径 
  154.      * @return 
  155.      */  
  156.     public static Size getBitMapSize(String path) {  
  157.         File file = new File(path);  
  158.         if (file.exists()) {  
  159.             InputStream in = null;  
  160.             try {  
  161.                 in = new FileInputStream(file);  
  162.                 BitmapFactory.decodeStream(in, null, OPTIONS_GET_SIZE);  
  163.                 return new Size(OPTIONS_GET_SIZE.outWidth,  
  164.                         OPTIONS_GET_SIZE.outHeight);  
  165.             } catch (FileNotFoundException e) {  
  166.                 return ZERO_SIZE;  
  167.             } finally {  
  168.                 closeInputStream(in);  
  169.             }  
  170.         }  
  171.         return ZERO_SIZE;  
  172.     }  
  173.   
  174.     // ------------------------------------------------------------------ private Methods  
  175.     // 将图片加入队列头  
  176.     private static Bitmap useBitmap(String path, int width, int height) {  
  177.         Bitmap bitMap = null;  
  178.         String key = createKey(path, width, height);  
  179.         synchronized (LOCKED) {  
  180.             bitMap = IMG_CACHE_INDEX.get(key);  
  181.             if (null != bitMap) {  
  182.                 if (CACHE_ENTRIES.remove(key)) {  
  183.                     CACHE_ENTRIES.addFirst(key);  
  184.                 }  
  185.             }  
  186.         }  
  187.         return bitMap;  
  188.     }  
  189.   
  190.     // 回收最后一张图片  
  191.     private static void destoryLast() {  
  192.         synchronized (LOCKED) {  
  193.             String key = CACHE_ENTRIES.removeLast();  
  194.             if (key.length() > 0) {  
  195.                 Bitmap bitMap = IMG_CACHE_INDEX.remove(key);  
  196.                 if (bitMap != null && !bitMap.isRecycled()) {  
  197.                     bitMap.recycle();  
  198.                     bitMap = null;  
  199.                 }  
  200.             }  
  201.         }  
  202.     }  
  203.   
  204.     // 创建键  
  205.     private static String createKey(String path, int width, int height) {  
  206.         if (null == path || path.length() == 0) {  
  207.             return "";  
  208.         }  
  209.         return path + "_" + width + "_" + height;  
  210.     }  
  211.   
  212.     // 通过图片路径,宽度高度创建一个Bitmap对象  
  213.     private static Bitmap createBitmap(String path, int width, int height) {  
  214.         File file = new File(path);  
  215.         if (file.exists()) {  
  216.             InputStream in = null;  
  217.             try {  
  218.                 in = new FileInputStream(file);  
  219.                 Size size = getBitMapSize(path);  
  220.                 if (size.equals(ZERO_SIZE)) {  
  221.                     return null;  
  222.                 }  
  223.                 int scale = 1;  
  224.                 int a = size.getWidth() / width;  
  225.                 int b = size.getHeight() / height;  
  226.                 scale = Math.max(a, b);  
  227.                 synchronized (OPTIONS_DECODE) {  
  228.                     OPTIONS_DECODE.inSampleSize = scale;  
  229.                     Bitmap bitMap = BitmapFactory.decodeStream(in, null,  
  230.                             OPTIONS_DECODE);  
  231.                     return bitMap;  
  232.                 }  
  233.             } catch (FileNotFoundException e) {  
  234.                 e.printStackTrace();  
  235.             } finally {  
  236.                 closeInputStream(in);  
  237.             }  
  238.         }  
  239.         return null;  
  240.     }  
  241.       
  242.     // 关闭输入流  
  243.     private static void closeInputStream(InputStream in) {  
  244.         if (null != in) {  
  245.             try {  
  246.                 in.close();  
  247.             } catch (IOException e) {  
  248.                 e.printStackTrace();  
  249.             }  
  250.         }  
  251.     }  
  252.   
  253.     // 图片大小  
  254.     static class Size {  
  255.         private int width, height;  
  256.   
  257.         Size(int width, int height) {  
  258.             this.width = width;  
  259.             this.height = height;  
  260.         }  
  261.   
  262.         public int getWidth() {  
  263.             return width;  
  264.         }  
  265.   
  266.         public int getHeight() {  
  267.             return height;  
  268.         }  
  269.     }  
  270.   
  271.     // 队列缓存参数对象  
  272.     static class QueueEntry {  
  273.         public String path;  
  274.         public int width;  
  275.         public int height;  
  276.     }  
  277. }  
时间: 2024-11-18 10:05:41

android 加载图片轻松避免OOM(out of memory)的相关文章

android 加载图片轻松避免OOM(out of memory) 支持设置缓存大小,不再强制catch OOM

http://blog.csdn.net/liaoxingliao/article/details/7168500 package l.test1.util; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import android.graphics

Android加载图片内存溢出问题解决方法

  这篇文章主要介绍了Android加载图片内存溢出问题解决方法,本文讲解使用BitmapFactory.Options解决内存溢出问题,需要的朋友可以参考下 1. 在Android软件开发过程中,图片处理是经常遇到的. 在将图片转换成Bitmap的时候,由于图片的大小不一样,当遇到很大的图片的时候会出现超出内存的问题,为了解决这个问题Android API提供了BitmapFactory.Options这个类. 2. 由于Android对图片使用内存有限制,若是加载几兆的大图片便内存溢出.Bi

版本控制-android加载图片的时候图片控件是黑色的

问题描述 android加载图片的时候图片控件是黑色的 我使用我自己写的ImageView进行加载图片,报出cannot generate texture from bitmap的错误,而且图片控件是黑色的,百度搜了,说是因为设置图片的非硬件加速模式是在api11之后添加的,要进行版本控制,我进行控制了,程序直接停止了,我想问问是不是我写得ImageView有问题?下面是我的ImageView类: public class Imageview extends ImageView implemen

android 加载图片oom若干方案小结

本文根据网上提供的一些技术方案加上自己实际开发中遇到的情况小结. 众所周知,每个Android应用程序在运行时都有一定的内存限制,限制大小一般为16MB或24MB(视手机而定).一般我们可以通过获取当前线程的可运行内存来判断,比如系统分给当前运行内存只有16M,而你的图片就有16M,这肯定会oom的. 相关知识介绍 1.颜色模型 常见的颜色模型有RGB.YUV.CMYK等,在大多数图像API中采用的都是RGB模型,Android也是如此:另外,在Android中还有包含透明度Alpha的颜色模型

android加载大图,防止oom

高效加载大图片 我们在编写Android程序的时候经常要用到许多图片,不同图片总是会有不同的形状.不同的大小,但在大多数情况下,这些图片都会大于我们程序所需要的大小.比如说系统图片库里展示的图片大都是用手机摄像头拍出来的,这些图片的分辨率会比我们手机屏幕的分辨率高得多.大家应该知道,我们编写的应用程序都是有一定内存限制的,程序占用了过高的内存就容易出现OOM(OutOfMemory)异常.我们可以通过下面的代码看出每个应用程序最高可用内存是多少. [java] view plaincopy in

Android加载图片内存溢出问题解决方法_Android

1. 在Android软件开发过程中,图片处理是经常遇到的. 在将图片转换成Bitmap的时候,由于图片的大小不一样,当遇到很大的图片的时候会出现超出内存的问题,为了解决这个问题Android API提供了BitmapFactory.Options这个类. 2. 由于Android对图片使用内存有限制,若是加载几兆的大图片便内存溢出.Bitmap会将图片的所有像素(即长x宽)加载到内存中,如果图片分辨率过大,会直接导致内存OOM,只有在BitmapFactory加载图片时使用BitmapFact

Android加载图片小结

应用中用到图片加载需要解决的问题 无网络环境下图片不可用 图片的本地缓存,或者默认预加载的图片 低配置机型,加载图像资源超内存(OutOfMemory, OoM) 需要合理使用内存,尤其是bitmap的使用,是内存溢出的最常见地方 ListView, GridView等控件 初始化或者移动过程中,列表项的重复绘制导致图片重复加载多次 列表快速滑动后,停止区域图像没有被快速加载 快速滑动过程中,在getView中进行图像加载逻辑,在随后view被复用于加载另外的不同的图片 前一个加载应该立即被取消

Android开发之加载图片的方法_Android

本文实例讲述了Android开发之加载图片的方法.分享给大家供大家参考.具体分析如下: 加载网络上的图片需要在manifest中配置访问网络的权限,如下: <uses-permission android:name="android.permission.INTERNET" /> 如果不配置这个权限的话,会报错:unknown host exception. package com.example.loadimgfromweb; import java.io.InputSt

Android使用控件ImageView加载图片的方法_Android

在 Android 加载图片一般使用 ImageView,这里简单记录一下这个控件的使用方法. 最简单就是在 xml 里直接使用 ImageView 标签: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="