Java.lang.OutOfMemoryError:位图大小超出VM预算 - Android

160
我开发了一款在Android上使用大量图像的应用程序。该应用程序运行一次,在屏幕上填充信息(布局、列表视图、文本视图、图像视图等),用户读取信息。没有动画、特效或任何会占用内存的东西。有时可绘制的对象可能会更改。有些是Android资源,有些是保存在SDCARD文件夹中的文件。然后用户退出(执行onDestroy方法,应用程序由VM保留在内存中),然后在某个时间点再次进入。每次用户进入应用程序时,我都可以看到内存越来越多,直到用户收到java.lang.OutOfMemoryError。所以处理许多图像的最佳/正确方法是什么?我应该将它们放入静态方法中,以便不必一直加载它们吗?我需要以特殊的方式清理布局或在布局中使用的图像吗?

4
如果你有许多可绘制的图形在不断变化,这可能会有所帮助。 这个方法是有效的,因为我自己也使用了这个程序 :) http://androidactivity.wordpress.com/2011/09/24/solution-for-outofmemoryerror-bitmap-size-exceeds-vm-budget/ - user964099
13个回答

0

我已经尝试了互联网上找到的所有方法,但都没有奏效。调用System.gc()只会拖慢应用程序的速度。在onDestroy中回收位图对我也没有用。

现在唯一有效的方法是拥有一个静态列表,其中包含所有位图,以便位图在重新启动后仍然存在。并且每次活动重新启动时,只需使用保存的位图而不是创建新的位图即可。

在我的情况下,代码如下:

private static BitmapDrawable currentBGDrawable;

if (new File(uriString).exists()) {
    if (!uriString.equals(currentBGUri)) {
        freeBackground();
        bg = BitmapFactory.decodeFile(uriString);

        currentBGUri = uriString;
        bgDrawable = new BitmapDrawable(bg);
        currentBGDrawable = bgDrawable;
    } else {
        bgDrawable = currentBGDrawable;
    }
}

这不会泄露你的上下文吗?(活动数据) - Rafael Sanches

0

我遇到了同样的问题,只是在使用合理大小的背景图片时进行切换。在放入新图片之前,将ImageView设置为null可以获得更好的结果。

ImageView ivBg = (ImageView) findViewById(R.id.main_backgroundImage);
ivBg.setImageDrawable(null);
ivBg.setImageDrawable(getResources().getDrawable(R.drawable.new_picture));

0

顺便说一下,这是我编写并使用了几个月的轻量级位图缓存。它不是所有功能都有,所以在使用之前请先阅读代码。

/**
 * Lightweight cache for Bitmap objects. 
 * 
 * There is no thread-safety built into this class. 
 * 
 * Note: you may wish to create bitmaps using the application-context, rather than the activity-context. 
 * I believe the activity-context has a reference to the Activity object. 
 * So for as long as the bitmap exists, it will have an indirect link to the activity, 
 * and prevent the garbaage collector from disposing the activity object, leading to memory leaks. 
 */
public class BitmapCache { 

    private Hashtable<String,ArrayList<Bitmap>> hashtable = new Hashtable<String, ArrayList<Bitmap>>();  

    private StringBuilder sb = new StringBuilder(); 

    public BitmapCache() { 
    } 

    /**
     * A Bitmap with the given width and height will be returned. 
     * It is removed from the cache. 
     * 
     * An attempt is made to return the correct config, but for unusual configs (as at 30may13) this might not happen.  
     * 
     * Note that thread-safety is the caller's responsibility. 
     */
    public Bitmap get(int width, int height, Bitmap.Config config) { 
        String key = getKey(width, height, config); 
        ArrayList<Bitmap> list = getList(key); 
        int listSize = list.size();
        if (listSize>0) { 
            return list.remove(listSize-1); 
        } else { 
            try { 
                return Bitmap.createBitmap(width, height, config);
            } catch (RuntimeException e) { 
                // TODO: Test appendHockeyApp() works. 
                App.appendHockeyApp("BitmapCache has "+hashtable.size()+":"+listSize+" request "+width+"x"+height); 
                throw e ; 
            }
        }
    }

    /**
     * Puts a Bitmap object into the cache. 
     * 
     * Note that thread-safety is the caller's responsibility. 
     */
    public void put(Bitmap bitmap) { 
        if (bitmap==null) return ; 
        String key = getKey(bitmap); 
        ArrayList<Bitmap> list = getList(key); 
        list.add(bitmap); 
    }

    private ArrayList<Bitmap> getList(String key) {
        ArrayList<Bitmap> list = hashtable.get(key);
        if (list==null) { 
            list = new ArrayList<Bitmap>(); 
            hashtable.put(key, list); 
        }
        return list;
    } 

    private String getKey(Bitmap bitmap) {
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        Config config = bitmap.getConfig();
        return getKey(width, height, config);
    }

    private String getKey(int width, int height, Config config) {
        sb.setLength(0); 
        sb.append(width); 
        sb.append("x"); 
        sb.append(height); 
        sb.append(" "); 
        switch (config) {
        case ALPHA_8:
            sb.append("ALPHA_8"); 
            break;
        case ARGB_4444:
            sb.append("ARGB_4444"); 
            break;
        case ARGB_8888:
            sb.append("ARGB_8888"); 
            break;
        case RGB_565:
            sb.append("RGB_565"); 
            break;
        default:
            sb.append("unknown"); 
            break; 
        }
        return sb.toString();
    }

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接