【问题标题】:Drawable vs Single reusable Bitmap better with memory?Drawable vs Single reusable Bitmap 更好的内存?
【发布时间】:2011-10-26 01:32:15
【问题描述】:

据我了解(不是我说得对)当应用程序完成时,Drawables 通常会正确地从内存中删除。然而,位图需要手动回收,有时甚至需要编写一个特殊的类来正确处理它们。 我的问题是,关于内存和泄漏,像这样简单地坚持使用 Drawables 是否更有益

myView.setBackgroundDrawable(getResources().getDrawable(R.drawable.my_image));
myView1.setBackgroundDrawable(getResources().getDrawable(R.drawable.my_image1));
myView2.setBackgroundDrawable(getResources().getDrawable(R.drawable.my_image2));

而不是像位图这样的东西:

Bitmap tmpBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image);
myView.setImageBitmap(tmpBitmap);

tmpBitmap.recycle();
tmpBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image1);
myView1.setImageBitmap(tmpBitmap);

tmpBitmap.recycle();
tmpBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.my_image2);
myView2.setImageBitmap(tmpBitmap);
tmpBitmap.recycle();

我当然也读过,您必须小心位图上的 recycle() 方法,因为它们可以在仍在使用时被删除?似乎这些问题不断以不同的形式出现,但我真的无法从任何人那里得到一个直接的答案。有人说要重用 Bitmap 并在每次使用后回收,还有人说使用 Drawables 和 unbindDrawables() 方法(这是我一直在使用的):

private void unbindDrawables(View view) {
    if (view.getBackground() != null) {
        view.getBackground().setCallback(null);
    }
    if (view instanceof ViewGroup) {
        for (int i = 0; i < ((ViewGroup) view).getChildCount(); i++) {
            unbindDrawables(((ViewGroup) view).getChildAt(i));
        }
        ((ViewGroup) view).removeAllViews();
    }
}

任何适用的见解将不胜感激。谢谢

【问题讨论】:

    标签: android memory bitmap drawable recycle


    【解决方案1】:

    位图不需要手动回收。它们像 Drawable 和其他对象一样被垃圾收集。同样,您不需要取消绑定可绘制对象,除非在非常特殊的情况下。您似乎阅读了很多误导性信息。

    在某些情况下(例如,如果您的应用处理大量位图数据或以静态方式存储可绘制对象),回收位图和取消绑定 drawable 可能很有用。

    您在问题开头显示的两个示例是等效的。如果您直接加载可绘制对象,则将代表您加载位图。如果您手动加载位图并将其设置在 ImageView 上,它们将代表您包含在可绘制对象中。

    使用第一个解决方案,因为它更简单,并且在您真正需要它们之前不必担心解除绑定和其他内存管理技术。

    【讨论】:

    • 我问的原因是因为我确实需要内存管理技术。我通过单击一个按钮来操作多个视图的图像,这就是我的菜单系统。这很好,除非我滚动浏览每个菜单,然后退出,然后再做一遍。几次后,应用程序因“位图超出 VM 限制 OOM”而崩溃。不确定为什么会这样做,但是当我使用 unbindDrawables() 方法时它不会发生。或者至少我还不能重新创建它。
    • 你必须非常小心预蜂窝位图。 Pre-Honeycomb,位图分配在 Java 垃圾收集器无法到达的 RAM 空间中。这会导致内存泄漏。如果您使用的是 Honeycomb 及更高版本,那么您是正确的。
    • 位图在本机堆上分配的事实不会导致内存泄漏。这只是意味着您必须等待终结器运行才能释放位图。
    【解决方案2】:

    我支持 Romain 的提议,但我不确定您的问题是否解决了您的实际问题。我不知道您如何处理对您的视图的引用。也许您只是在应用程序中存在内存泄漏? Android 中的很多内存泄漏都与Context 有关。当Drawable 附加到View 时,View 被设置为Drawable 上的回调。

    TextView myView = new TextView(this);
    myView.setBackgroundDrawable(getDrawable(R.drawable.my_bitmap));
    

    在上面的代码 sn-p 中,这意味着 Drawable 引用了 TextView,而 TextView 本身又引用了 ActivityContext),而 Context 又引用了几乎所有内容取决于你的代码。

    如果不查看您的更多代码,我猜您在 Activity 被销毁时将存储的可绘制对象的回调设置为 null 是在正确的轨道上。

    【讨论】:

    • 谢谢,非常好的信息。我通过 findViewById(R.Id.Image_name);顺便提一句。不确定这是否会以某种方式留下对上下文的引用。
    猜你喜欢
    • 2012-08-19
    • 2020-12-24
    • 1970-01-01
    • 2012-01-26
    • 2017-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    相关资源
    最近更新 更多