[英]Android setMovementMethod on a TextView inside a ListView
[英]Android TextView leaks with setMovementMethod
我有一个ListView
并且在它的adapter
的getView
方法中,我返回一个带有MyButton
的RelativeLayout
。
MyButton
有一个textView
,里面有可点击的词( ClickableSpan
)。
为了完成这项工作,我从以下行开始: textView.setMovementMethod(LinkMovementMethod.getInstance());
一切完美,但MAT显示, MyButton
泄漏,因为textView
。 当我注释掉上面的行时,没有任何泄漏。
我应当设置movementMethod
到null
? 但即使是这样,我也不知道按钮的销毁时刻将其设置为null
因为它在许多其他视图中。
我究竟做错了什么? 如何防止这种泄漏?
更新
通过在onDetachedFromWindow
文本设置为空字符串解决了泄漏onDetachedFromWindow
,但我仍在尝试查找与此行为相关的文档。 为什么我应该将textview
设置为""
?
在Fragment
创建超链接时,我遇到了TextView
、 ClickableSpan
和LinkMovementMethod
另一个内存泄漏。 第一次点击设备的超链接和旋转后,由于NPE无法再次点击。
为了弄清楚发生了什么,我进行了调查,这是结果。
TextView
在onSaveInstanceState()
期间将包含ClickableSpan
的字段mText
的副本保存到静态内部类SavedState
的实例中。 它仅在特定条件下发生。 在我的例子中,它是可点击部分的一个Selection
,它是在第一次点击跨度后由LinkMovementMethod
设置的。
接着,如果存在已保存的状态中, TextView
执行恢复为字段mText
,包括所有的跨度,从TextView.SavedState.text
期间onRestoreInstanceState()
这是一个有趣的部分。 何时onRestoreInstanceState()
? 它在onStart()
之后onStart()
。 我在onCreateView()
设置了一个ClickableSpan
的新对象,但是在onStart()
,旧对象替换了新对象,这导致了大问题。
因此,解决方案非常简单,但没有记录 - 在onStart()
期间执行ClickableSpan
设置。
您可以在我的博客TextView、ClickableSpan 和内存泄漏上阅读完整调查 ,并使用示例项目。
即使在高于KitKat
版本上,使用ClickableSpan
仍可能导致泄漏。 如果您查看ClickableSpan
实现,您会注意到它没有扩展NoCopySpan
,因此它在onSaveInstanceState()
泄漏,如@DmitryKorobeinikov 和@ChrisHorner 的答案中所述。 因此,解决方案是创建一个扩展ClickableSpan
和NoCopySpan
的自定义类。
class NoCopyClickableSpan(
private val callback: () -> Unit
) : ClickableSpan(), NoCopySpan {
override fun onClick(view: View) {
callback()
}
}
编辑事实证明,当启用辅助功能服务时,此修复会导致某些设备崩溃。
您的问题很可能是由NoCopySpan
引起的。 在 KitKat 之前,TextView 会复制 span 并使用 SpannableString 将其放置在onSaveInstanceState()
中的 Bundle 中。 由于某种原因,SpannableString 不会删除 NoCopySpans,因此保存的状态包含对原始 TextView 的引用。 此问题已在后续版本中修复。
将文本设置为 "" 可以解决此问题,因为包含 NoCopySpan 的原始文本已正确 GC。
LeakCanary建议的解决方法是......
Hack:要解决此问题,您可以覆盖 TextView.onSaveInstanceState(),然后使用反射访问 TextView.SavedState.mText 并清除 NoCopySpan 跨度。
可以在此处找到LeakCanary 对此泄漏的排除条目。
尝试在onStart()
方法中初始化 ClickableSpan。喜欢
onStart(){
super.onStart()
someTextView.setText(buildSpan());
}
某些 Android 版本上的 Span 存在问题。 有时它会导致内存泄漏。 本文中的更多信息TextView、ClickableSpan 和内存泄漏
我希望它会有所帮助。
在花了几个小时尝试这些答案后,我想出了自己的答案,最终奏效了。
我不确定这是多么准确,也不明白为什么会这样,但结果证明在onDestroy()
中将我的TextView
的运动方法设置为 null 解决了这个问题。
如果有人知道为什么请告诉我。 我很困惑,因为LinkMovementMethod.getInstance()
似乎没有对TextView
或活动的引用。
这是代码
override fun onStart() {
...
text_view.text = spanString
text_view.movementMethod = LinkMovementMethod
}
override fun onDestroy() {
text_view.text = ""
text_view.movementMethod = null
}
它在没有设置text_view.text = ""
情况下工作,但我保留了它,因为@Chris Horner 回答说在 KitKat 之前可能存在问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.