如果Android的回调被重置,为什么Android会因静态Drawable泄漏内存?

Jag*_*uar 12 java android memory-leaks

我只是关注如何避免内存泄漏的文章:android开发人员博客 以下是使用的代码段:

private static Drawable sBackground;

@Override
protected void onCreate(Bundle state) {
  super.onCreate(state);

  TextView label = new TextView(this);
  label.setText("Leaks are bad");

  if (sBackground == null) {
    sBackground = getDrawable(R.drawable.large_bitmap);
  }
  label.setBackgroundDrawable(sBackground);

  setContentView(label);
}
Run Code Online (Sandbox Code Playgroud)

据说drawable有一个对textview的回调引用(并间接对该活动); 这将在旋转时保留 - 因此内存泄漏.

我的查询是不会在旋转时重置drawable的回调 - 它将获得新的textview(它将保存新的上下文).因此允许以前的textview/context实例进行GC.

编辑:我得到的答案是如何"解决"问题 - 我不是在寻找!请重新阅读查询.我正在添加更多细节.启动活动时,引用是:

Drawable1 - > TextView1 - > Activity1

旋转时,Activity1和TextView1被销毁但不是Drawable1

Drawable1 - > TextView2 - > Activity2

这意味着,Activity1和TextView1可以自由地进行GC控制 - 因为没有其他对象可以引用它们.那么什么是泄漏?

这个理解我错了吗?或者,Drawable可以将多个视图作为回调吗?(查看源代码,我没有看到Drawable上的回调列表).

Dou*_*ond 9

如果您旋转设备,MyActivity则会重新创建相同的类(或您给它的任何名称),覆盖回调并且泄漏一直存在,直到下一个GC.当您导航到另一个活动时,问题在于保留对旧活动的引用.今天,这是缓解,因为setCallback现在存储在一个回调WeakReference,你可以看到在当前绘制对象的代码,但它是一个有力的参考一次(搜索setCallback(Callback cb)).无论如何,你是对的,如果你只是查看一个活动,回调将在旋转后重置.

(编辑,添加段落): 例如:MainAcivity @ 1是第一个实例.旋转时,它会被破坏并创建一个新的MainActivity @ 2.首先,有一个泄漏,但一旦sDrawable重新分配,MainActivity @ 1可以自由收集,没有问题.现在假设您不是旋转,而是导航到SecondActivity.现在,sDrawable只是为了MainActivity并且仍然保留对MainActivity @ 2的引用,所以它泄漏了.

看到这段代码:

package com.douglasdrumond.leaky;

import android.os.Bundle;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import android.widget.TextView;

public class MainActivity extends Activity {
    private static Drawable sBackground;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        TextView label = new TextView(this);
        System.gc();
        long memory = Runtime.getRuntime().totalMemory()
                - Runtime.getRuntime().freeMemory();
        label.setText("Memory: " + memory / 1024f);

        if (sBackground == null) {
            sBackground = getResources().getDrawable(R.drawable.large_bitmap);
        }
        label.setBackgroundDrawable(sBackground);

        setContentView(label);
    }

}
Run Code Online (Sandbox Code Playgroud)

显然,旋转不会增加内存使用量.