内存泄漏使用LayoutInflater来扩充XML

时间:2013-01-17 17:11:17

标签: android memory-leaks android-actionbar

我面临一个非常奇怪的问题。我有一个ActivityActionBar包含自定义视图。

如果我加载此自定义视图的XML,请执行以下操作:

LayoutInflater inflater = LayoutInflater.from(this);
ViewGroup vg = (ViewGroup) inflater.inflate(R.layout.action_search_form,null);

它泄漏:活动不是GC'd。以下修复有效(为什么?):

LayoutInflater inflater = LayoutInflater.from(getApplicationContext());

但是,如果我在子视图上设置OnClickListener,它会再次泄漏:

ImageButton clear = (ImageButton) vg.findViewById(...);
clear.setOnClickListener(new View.OnClickListener() {

   @Override
   public void onClick(View v) {
            // Even if empty
        }
    });
}

所有这些都发生在活动的私有方法中,所有视图都是局部变量。

我发现了一个修复但不明白为什么会有效:视图很简单所以我用Java编写代码而不是膨胀XML。我怀疑它与以下事实有关:没有上下文传递给LayoutInflater,并且没有任何事情发生在Activity本身,但如果有人可以帮助我理解发生了什么,我会非常感激。

1 个答案:

答案 0 :(得分:2)

所有View类都需要Context参数。在扩展XML时,提供给创建的View的上下文与提供给LayoutInflater的上下文相同。您的观点保留了对您的活动的引用。

当你使用getApplicationContext()并且Activity没有泄漏的原因是你将一个全局的上下文传递给应用程序的整个生命周期,而不仅仅是活动。

**编辑**

关于为什么OnClickListener也保留你的Activity,这是因为使用匿名内部类的副作用。默认情况下,这些内联实现保留对父/包装类实例的引用。这样你就可以从内部的实现中调用父方法。

例如:

myView.setOnClickListener(new View.OnClickListener() {
    public void onClick(View v) {
        MyActivity.this.doSomethingCool();
    }
}

无论方法体中是否有任何内容,内部类仍然保持对父类的引用。