【问题标题】:Android telling me my bitmap is recycled before I've actually recycled itAndroid 告诉我我的位图在我实际回收之前已被回收
【发布时间】:2015-03-02 16:24:56
【问题描述】:

我从 XML 中得到我的位图:

//Get bitmap from drawable
bd = (BitmapDrawable) view.getResources().getDrawable(R.drawable.backgrounds);
backgrounds = bd.getBitmap();

//Do required work with bitmap (Will just use a log statement here for testing
Log.v("NewTag","Testing: "+bd.getBitmap().getPixel(0, 0));

//Now recycle this large bitmap
bd.getBitmap.recycle();
bd=null;
backgrounds.recycle();
backgrounds=null;

我第一次运行这段代码时,一切都很好。但是,当我退出我的应用程序(使用返回键),然后重新启动应用程序时,它可能或可能不工作。有时,我得到一个错误:

无法在回收的位图上调用 getPixel()

为什么?我什至还没有回收它。或者更准确地说,它似乎不是在重新创建位图并记住上次的循环。

如果我使用 BitmapFactory 获取位图,则不会发生此问题(不幸的是,我不能这样做,因为我必须从 XML 别名中获取此特定位图)。

同样在安装 Lollipop 之前,这工作正常(只要我有 bd = null)。

我已经连续 2 天遇到这个问题,所以如果有人能解释一下,我将非常感激。

编辑

我尝试过@aga 的建议,即根本不回收/清空bd,但这没有什么区别。位图在重新创建后仍然“已经”回收(再次,间歇性地)。

另外,当像这样记录时:

Log.v("NewTag","Backgrounds: "+backgrounds);

我注意到当它失败时,记录的引用与上次相同。所以.....

【问题讨论】:

    标签: java android memory bitmap recycle


    【解决方案1】:

    有趣的问题。我很确定,Android 背后有一些优化的想法。

    如果您确实需要 XML 的位图:

        Resources res = new Resources(getAssets(), new DisplayMetrics(), new Configuration());
    
        bd = (BitmapDrawable) res.getDrawable(R.drawable.bitmap_drawable);
        backgrounds = bd.getBitmap();
    
        ......
    
        bd.getBitmap().recycle();
        bd=null;
        backgrounds.recycle();
        backgrounds=null;
    

    您可以先尝试从标准getResources() 获取Bitmap,然后再实例化新的资源实例。

    如果您不需要需要 XML 的位图:

     Bitmap backgrounds = BitmapFactory.decodeResource(getResources(), R.drawable.test_image);
    

    获取图片和

     backgrounds.recycle();
     backgrounds=null;
    

    回收它。

    希望对你有帮助。

    【讨论】:

    • 感谢@KonstantinLoginov,但请看这个(引自问题):“如果我使用 BitmapFactory 获取位图,则不会发生此问题(不幸的是,我不能这样做,因为我必须这样做从 XML 别名中获取此特定位图)。”
    • @Zippy 你还没有想出解决方案吗?我有同样的问题。我目前正在删除所有回收代码并等待答案
    • 不幸的是@JayVDiyk 我从来没有找到解决这个问题的方法,就像你说的那样,根本不回收位图!
    • @Zippy 我想,我找到了,检查一下!
    • @JayVDiyk 我想,我找到了,检查一下!
    【解决方案2】:

    Resources 类有 caches for resources loaded from your APK。当您回收DrawableBitmap 时,您会破坏缓存的对象。 Resources 缓存无法知道这一点,因此它们会在您下次请求该资源时愉快地返回相同的对象。

    当您的应用进程终止时,所有内存状态都会丢失,包括资源缓存 - 所以一切都会再次运行(一次)。请注意,“退出”应用程序或销毁 Activity 并不一定意味着您的进程将死亡。

    【讨论】:

    • 在应用关闭之前不回击是否意味着应用已完全关闭?
    • 如果你按回,你的activity还在最近的应用下打开吗?尝试从那里移除它,而不是它应该完全关闭。
    • @JayVDiyk:不,它没有。在这种情况下,您的 Activity 将被销毁,但您的 进程 很可能还活着。 Android 保留它以加快同一应用程序的未来发布。这就是内存统计中所谓的“缓存进程”或“空进程”。系统会根据需要自动清理这些进程。您可以在此处阅读有关流程生命周期的更多信息:developer.android.com/guide/topics/processes/…
    • @SnildDolkow 那么有什么解决方法吗?谢谢你的回答。
    • 我认为“不要回收从 Resources 获取的图像”是你最好的选择。
    【解决方案3】:

    正如@snild Dolkow 所述,发生这种行为是因为位图存储在资源缓存中,当您尝试再次获取它时,您将获得回收的位图。

    我认为解决方案是在必要时使用save the bitmap to internal storagereload it from storage

    此解决方案的开销是您必须在使用完图像文件后将其删除。

    【讨论】:

    • 还有一遍又一遍地重新加载该图像的开销......似乎没有必要。
    猜你喜欢
    • 2012-06-15
    • 1970-01-01
    • 2011-12-22
    • 2017-03-12
    • 2014-03-07
    • 1970-01-01
    • 1970-01-01
    • 2012-07-20
    • 2012-08-09
    相关资源
    最近更新 更多