2012-12-28 74 views
15

简介:的EditText造成内存泄漏

我有具有以下结构的应用程序: 动作条向上顶(ActionBarSherlock) ViewPagerIndicator低于(制表符) ViewPager(主机片段)

我有一个问题,我的一个碎片导致了相当大的内存泄漏。我将问题缩小到以下情况:

导致泄漏的片段除了使其onCreateView方法中的布局膨胀外,什么都没做。这是通过以下方式完成的:

return inflater.inflate(R.layout.filter_auctions_fragment, container, false); 

这里没什么不寻常的。

布局文件只包含一个ScrollView,LinearLayout和两个EditText(其中包括更常见的东西,但我把问题缩小到只是这些意见,使其简单)。现在用于添加片段的代码: mTab​​sAdapter.addTab(tabName,ProblematicFragment.class);

mTabsAdapterTabsAdapter的一个实例,它扩展了支持库的FragmentPagerAdapter。这是相当标准的,所以我不包括来源以尽可能缩短这个问题。

现在有趣的部分:

这是当我转动我的设备来回几次用什么堆发生了:

12-28 12:26:27.180: D/dalvikvm(18841): GC_CONCURRENT freed 530K, 7% free 10701K/11436K, paused 4ms+7ms, total 58ms 
12-28 12:26:27.180: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 24ms 
12-28 12:26:28.270: D/dalvikvm(18841): GC_CONCURRENT freed 737K, 8% free 11048K/11964K, paused 4ms+5ms, total 53ms 
12-28 12:26:29.510: D/dalvikvm(18841): GC_CONCURRENT freed 789K, 8% free 11464K/12436K, paused 5ms+5ms, total 42ms 
12-28 12:26:30.640: D/dalvikvm(18841): GC_CONCURRENT freed 888K, 9% free 11919K/12984K, paused 4ms+5ms, total 52ms 
12-28 12:26:31.810: D/dalvikvm(18841): GC_CONCURRENT freed 903K, 8% free 12421K/13500K, paused 3ms+8ms, total 58ms 
12-28 12:26:33.800: D/dalvikvm(18841): GC_CONCURRENT freed 1092K, 9% free 13005K/14272K, paused 4ms+6ms, total 59ms 
12-28 12:26:33.800: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 20ms 
12-28 12:26:36.000: D/dalvikvm(18841): GC_CONCURRENT freed 1355K, 11% free 13518K/15048K, paused 3ms+8ms, total 74ms 
12-28 12:26:36.000: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 19ms 
12-28 12:26:38.110: D/dalvikvm(18841): GC_CONCURRENT freed 1450K, 11% free 14106K/15720K, paused 3ms+11ms, total 72ms 
12-28 12:26:40.450: D/dalvikvm(18841): GC_CONCURRENT freed 1530K, 11% free 14807K/16516K, paused 2ms+15ms, total 75ms 
12-28 12:26:40.450: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 29ms 
12-28 12:26:43.030: D/dalvikvm(18841): GC_CONCURRENT freed 1682K, 11% free 15591K/17452K, paused 3ms+10ms, total 66ms 
12-28 12:26:43.030: D/dalvikvm(18841): WAIT_FOR_CONCURRENT_GC blocked 32ms 

显然,内存泄漏。 是的,我知道它导致活动从头开始重新创建,这是我想要的,因为我对横向和纵向模式有不同的布局。但它不应该导致内存泄漏。

我发现这个问题的根源。这是我前面提到的两个EditText。只要我将它们从布局中移除并进行相同的测试(来回旋转)。这些是我得到的GC消息:

12-28 12:21:41.270: D/dalvikvm(17934): GC_CONCURRENT freed 534K, 7% free 10853K/11576K, paused 3ms+7ms, total 44ms 
12-28 12:21:42.560: D/dalvikvm(17934): GC_CONCURRENT freed 818K, 9% free 11113K/12108K, paused 11ms+9ms, total 95ms 
12-28 12:21:44.680: D/dalvikvm(17934): GC_CONCURRENT freed 1036K, 10% free 11313K/12528K, paused 3ms+6ms, total 54ms 
12-28 12:21:44.680: D/dalvikvm(17934): WAIT_FOR_CONCURRENT_GC blocked 15ms 
12-28 12:21:47.420: D/dalvikvm(17934): GC_CONCURRENT freed 1089K, 10% free 11510K/12780K, paused 2ms+6ms, total 79ms 
12-28 12:21:47.420: D/dalvikvm(17934): WAIT_FOR_CONCURRENT_GC blocked 39ms 
12-28 12:21:50.200: D/dalvikvm(17934): GC_CONCURRENT freed 1317K, 12% free 11461K/12956K, paused 4ms+13ms, total 84ms 
12-28 12:21:53.210: D/dalvikvm(17934): GC_CONCURRENT freed 1629K, 14% free 11148K/12956K, paused 3ms+7ms, total 47ms 
12-28 12:21:55.580: D/dalvikvm(17934): GC_CONCURRENT freed 1056K, 13% free 11302K/12956K, paused 4ms+7ms, total 59ms 
12-28 12:21:57.280: D/dalvikvm(17934): GC_CONCURRENT freed 1306K, 14% free 11200K/12956K, paused 5ms+5ms, total 82ms 
12-28 12:21:59.420: D/dalvikvm(17934): GC_CONCURRENT freed 1035K, 12% free 11408K/12956K, paused 3ms+7ms, total 55ms 
12-28 12:22:01.990: D/dalvikvm(17934): GC_CONCURRENT freed 1392K, 13% free 11352K/12956K, paused 4ms+9ms, total 54ms 
12-28 12:22:01.990: D/dalvikvm(17934): WAIT_FOR_CONCURRENT_GC blocked 30ms 

现在就是我想看到的!

为什么!?

有人可以告诉我为什么会发生这种情况吗?我想补充一点,我并没有在我的应用程序的任何地方保留对这些对象的引用(我通常会这样做,但即使当我为了测试目的而删除它们时,仍然会发生泄漏)。

奖金 - 泄漏MAT截图:

Path to GC Roots (whtout soft/weak refs) for my Activity

Path to GC Roots (whtout soft/weak refs) for my "ProblematicFragment"

正如你可以看到有该片段和活动的16个实例,而应该只有一个。

编辑:

我注意到,当我手动添加片段在不同的活性(使用FragmentManager.beginTransaction())泄漏不会发生!!!我现在完全糊涂了......

EDIT2:

卸下EditText小号修复它的android:id属性...但现在他们很没用......

+1

您没有折叠打开MAT显示器的'originalText'部分以查看您的额外副本来自哪里。查看屏幕截图底部的第三行。 – CommonsWare

+0

也许这SO讨论相关 - http://stackoverflow.com/questions/8497965/why-does-editview-retain-its-activitys-context-in-ice-cream-sandwich –

+1

我有同样的问题,你有没有找到解决方案? – MobDev

回答

5

我有找到了适合我需求的解决方案。

我跟踪这个问题到widget.EditableInputConnection。我认为这是建议系统中的查询。它也负责坚持我的Activity,从而导致内存泄漏。

我不需要建议,所以我想将其关闭。然而事实证明这很困难。 EditText.setInputType没有工作,无论是在XML或代码。

我最终做了以下工作。神奇的是发生在onCreateInputConnection()

public class MyEditText extends TextView { 
    public MyEditText(Context context) { 
     this(context, null); 
    } 

    public MyEditText(Context context, AttributeSet attrs) { 
     this(context, attrs, android.R.attr.editTextStyle); 
    } 

    public MyEditText(Context context, AttributeSet attrs, int defStyle) { 
     super(context, attrs, defStyle); 
    } 

    @Override 
    public InputConnection onCreateInputConnection(EditorInfo outAttrs) { 
     return null; 
    } 

    @Override 
    protected boolean getDefaultEditable() { 
     return true; 
    } 

    @Override 
    protected MovementMethod getDefaultMovementMethod() { 
     return ArrowKeyMovementMethod.getInstance(); 
    } 

    @Override 
    public Editable getText() { 
     return (Editable) super.getText(); 
    } 

    @Override 
    public void setText(CharSequence text, BufferType type) { 
     super.setText(text, BufferType.EDITABLE); 
    } 

    /** 
    * Convenience for {@link Selection#setSelection(Spannable, int, int)}. 
    */ 
    public void setSelection(int start, int stop) { 
     Selection.setSelection(getText(), start, stop); 
    } 

    /** 
    * Convenience for {@link Selection#setSelection(Spannable, int)}. 
    */ 
    public void setSelection(int index) { 
     Selection.setSelection(getText(), index); 
    } 

    /** 
    * Convenience for {@link Selection#selectAll}. 
    */ 
    public void selectAll() { 
     Selection.selectAll(getText()); 
    } 

    /** 
    * Convenience for {@link Selection#extendSelection}. 
    */ 
    public void extendSelection(int index) { 
     Selection.extendSelection(getText(), index); 
    } 

    @Override 
    public void setEllipsize(TextUtils.TruncateAt ellipsis) { 
     if (ellipsis == TextUtils.TruncateAt.MARQUEE) { 
      throw new IllegalArgumentException("EditText cannot use the ellipsize mode " 
        + "TextUtils.TruncateAt.MARQUEE"); 
     } 
     super.setEllipsize(ellipsis); 
    } 
} 

在哪里,关键是要拒绝InputConnection。这将删除建议并消除内存泄漏。

希望这可以帮助你..

+1

魔法!请问你测试过哪些Android版本? –

+0

我还没有能够得到这个工作,我已经测试过的任何东西,模拟器17,18,19和N4。 – newfivefour

0

我正面临与三星Galaxy S3完全相同的问题。

solution from @aslakjo没有为我工作。我已建议禁用

我以XML布局中的EditText替换android:idandroid:tag而结束。现在它运行良好,包含在viewpager中的碎片在不再可见时正确收集垃圾,不要问我为什么。

此设备可能注册基于一个id存在的东西。