当前位置: 代码迷 >> Android >> android端读取本map片出现OutOfMemoryException
  详细解决方案

android端读取本map片出现OutOfMemoryException

热度:80   发布时间:2016-05-01 11:16:32.0
android端读取本地图片出现OutOfMemoryException

前些日子一直为图片内存溢出问题困扰着,查了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 )

  相关解决方案