簡體   English   中英

Android TextView 使用 setMovementMethod 泄漏

[英]Android TextView leaks with setMovementMethod

我有一個ListView並且在它的adaptergetView方法中,我返回一個帶有MyButtonRelativeLayout

MyButton有一個textView ,里面有可點擊的詞( ClickableSpan )。

為了完成這項工作,我從以下行開始: textView.setMovementMethod(LinkMovementMethod.getInstance());

一切完美,但MAT顯示, MyButton泄漏,因為textView 當我注釋掉上面的行時,沒有任何泄漏。

我應當設置movementMethodnull 但即使是這樣,我也不知道按鈕的銷毀時刻將其設置為null因為它在許多其他視圖中。

我究竟做錯了什么? 如何防止這種泄漏?

在此處輸入圖片說明

更新

通過在onDetachedFromWindow文本設置為空字符串解決了泄漏onDetachedFromWindow ,但我仍在嘗試查找與此行為相關的文檔。 為什么我應該將textview設置為""

Fragment創建超鏈接時,我遇到了TextViewClickableSpanLinkMovementMethod另一個內存泄漏。 第一次點擊設備的超鏈接和旋轉后,由於NPE無法再次點擊。

為了弄清楚發生了什么,我進行了調查,這是結果。

TextViewonSaveInstanceState()期間將包含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 的答案中所述。 因此,解決方案是創建一個擴展ClickableSpanNoCopySpan的自定義類。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM