[英]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.