Android TextView 使用 setMovementMethod 泄漏

fra*_*ish 5 android listview memory-leaks textview linkmovementmethod

我有一个ListView和它adaptergetView方法,我返回一个RelativeLayoutMyButton它里面。

MyButton有一个textView,我在里面有可点击的词 ( ClickableSpan)。

为了完成这项工作,我从以下行开始: textView.setMovementMethod(LinkMovementMethod.getInstance());

一切正常,但 MAT 显示MyButton泄漏是因为textView. 当我注释掉上面的行时,没有任何泄漏。

我应当设置movementMethodnull?但即使是这样,我也不知道按钮的破坏时刻将其设置null为在许多其他视图中。

我究竟做错了什么?如何防止这种泄漏?

在此处输入图片说明

更新

通过将 text 设置为里面的空字符串解决了泄漏问题onDetachedFromWindow,但我仍在尝试查找与此行为相关的文档。为什么要设置textview""

小智 5

我面临的另一个内存泄漏TextViewClickableSpan以及LinkMovementMethod同时里面做的超链接Fragment。第一次点击设备的超链接和旋转后,由于NPE无法再次点击。

为了弄清楚发生了什么,我进行了调查,这是结果。

TextView在进入静态内部类的实例期间mText,保存包含字段的副本。它仅在特定条件下发生。在我的例子中,它是可点击部分的 a ,它是在第一次点击跨度后设置的。ClickableSpanonSaveInstanceState()SavedStateSelectionLinkMovementMethod

接下来,如果存在已保存的状态,则从期间TextView对字段 进行恢复mText,包括所有跨度。TextView.SavedState.textonRestoreInstanceState()

这是一个有趣的部分。什么时候onRestoreInstanceState()叫?它在 之后调用onStart()。我设置了一个新对象ClickableSpaninonCreateView()但在onStart()旧对象替换新对象后,这导致了大问题。

因此,解决方案非常简单但没有记录 -ClickableSpanonStart().

您可以在我的博客TextView、ClickableSpan 和内存泄漏上阅读完整调查并使用示例项目


Chr*_*ner 2

您的问题很可能是由 引起的NoCopySpanonSaveInstanceState()在 KitKat 之前,TextView 会使用 SpannableString制作 Span 的副本并将其放置在 Bundle 中。由于某种原因,SpannableString 不会删除 NoCopySpans,因此保存的状态保存对原始 TextView 的引用。此问题已在后续版本中修复。

将文本设置为“”可以解决该问题,因为包含 NoCopySpan 的原始文本已正确 GC。

LeakCanary建议的解决方法是......

黑客:要解决此问题,您可以重写 TextView.onSaveInstanceState(),然后使用反射来访问 TextView.SavedState.mText 并清除 NoCopySpan 跨度。

可以在此处找到LeakCanary 针对此泄漏的排除条目。