在内存中缓存跨实例共享的单个Bitmap的最佳方法

时间:2014-11-13 08:58:04

标签: android caching bitmap

要在OpenGL中绘制我的精灵,我在多个对象中使用单个支持位图,如果尺寸足够大则重用Bitmap,如果太小则重新创建。目前我使用的是静态Bitmap对象,但我认为这会导致内存泄漏,即使我不确定。

那么,假设我需要在多个对象之间共享一个Bitmap,那么最好的方法是什么?

1)像我一样使用单个位图作为静态参考

2)使用静态弱引用(即使这里没有在android dev页面中建议http://developer.android.com/training/displaying-bitmaps/cache-bitmap.html

3)使用单例,然后在其中使用Bitmap(但这可能就像1)

4)使用LRU缓存,每次我需要更大的时候创建一个新的位图

2 个答案:

答案 0 :(得分:1)

1,3& 4基本上都是一样的。您可以直接为static创建Bitmap引用,也可以为包含引用的内容创建Application引用。当您使用static类来“锚定”该位图时,会发生同样的情况。该类由Android保留,并且在此上下文中与Activity引用相同。

这是否是内存泄漏取决于您的定义。泄漏的对象是通过无意的引用它们而对垃圾收集器保持安全的对象。因此,当您希望该引用保留位图时,它肯定不是泄漏。

缓存数据产生的问题与某些FragmentWeakReference的生命周期或更一般的术语"task"无关,即使数据存储器占用的内存也是如此用户永远不会回到您的应用程序。应用程序进程保持活动状态,直到Android决定它需要内存。您最后一次合法使用位图和Android最终杀死您的应用程序从而清理内存之间的时间可以被视为泄漏。

如果我们拥有神奇的力量,一旦我们知道将会发生这种情况,我们就可以简单地清理缓存。但是有一些现实的选择:

2)不是一种选择。如果您正在尝试使用SoftReference作为缓存,那么您还没有理解该类的用途是什么,而且我真的不明白为什么在文档中甚至提到它(弱引用的对象应该被垃圾收集为一旦没有人有强烈的参考,就尽可能快。)

Bitmap用于“缓存”,但使用它作为实际缓存不仅在Android上被破坏。它被设计破坏了,因为你让垃圾收集器有责任为你维护一个缓存而不告诉它如何确定对象的优先级或者在什么条件下应该保证多少内存。结果是GC将清理错误的东西或简单地清理所有东西。除了知道如何清理的适当缓存之外,还可以使用SoftReference。


除了所有这些之外:请注意单个{{1}}可能还不够。如果您查看Tasks and Back Stack,您可能已经注意到1个应用程序进程可以并行执行2个或更多独立任务。这意味着可能有任何Activity在不同阶段使用位图。如果您不想一直在这些位图之间覆盖缓存位图,则每个任务可能必须有1个位图。

我不知道如何按任务执行此操作,但您可以轻松使用保留的片段将位图的生命与活动的生命相关联(忽略屏幕旋转等):http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html /示例位图缓存https://github.com/google/iosched/blob/master/android/src/main/java/com/google/samples/apps/iosched/util/BitmapCache.java

答案 1 :(得分:0)

我认为最好的方法是使用硬参考创建Singleton以及一些回收和加载的方法,我创建了很多不同的方法Bitmap和图形加载器,这可能是最有效和最简单的访问方式

public class BitmapLoader{

    public static BitmapLoader bl;
    private static Bitmap b=null;

    public static BitmapLoader getInstance(){
        if(bl==null)
            bl = new BitmapLoader();
        return bl;
    }

    public Bitmap getBitmap(Context c){
        if(b==null && c!=null)
            b=loadBitmapUsingContectIfNeededOrWhateverYouWant(c);
        return b;
    }

    public void recycleBitmap(){ //for e.g. onDestroy() Activity or other
        if(b!=null)
            b.recycle();
    }

}

在LruCache中保持加载位图也是个好主意