Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android TextView leaks with setMovementMethod

I have a ListView and in it's adapter's getView method, I return a RelativeLayout with MyButton inside it.

MyButton has a textView and I have clickable words inside it (ClickableSpan).

To make this work, I start with thew following line: textView.setMovementMethod(LinkMovementMethod.getInstance());

Everything works perfectly but MAT shows that MyButton leaks because of textView. When I comment out the line above, nothing leaks.

Shall I set movementMethod to null? But even if so, I can't know the destruction moment of the button to set that to null as it is inside of many other views.

What am I doing wrong? How to prevent this leak?

enter image description here

update

Solved the leak by setting text to empty string inside onDetachedFromWindow, but I am still trying to find a documentation related to this behaviour. Why should I set the textview to ""?

like image 637
frankish Avatar asked Feb 16 '15 10:02

frankish


1 Answers

I faced another memory leak with TextView, ClickableSpan, and LinkMovementMethod while making hyperlinks inside a Fragment. After the first click on the hyperlink and rotation of the device, it was impossible to click it again due to NPE.

In order to figure out what's going on, I made an investigation and here is the result.

TextView saves a copy of the field mText, that contains ClickableSpan, during the onSaveInstanceState() into the instance of static inner class SavedState. It happens only under certain conditions. In my case, it was a Selection for the clickable part, which is set by LinkMovementMethod after the first click on the span.

Next, if there is a saved state, TextView performs restoration for the field mText, including all spans, from TextView.SavedState.text during onRestoreInstanceState().

Here is a funny part. When onRestoreInstanceState() is called? It’s called after onStart(). I set a new object of ClickableSpan in onCreateView() but after onStart() the old object replaces new one which leads to the big problems.

So, the solution is quite simple but is not documented – perform setup of ClickableSpan during onStart().

You can read the full investigation on my blog TextView, ClickableSpan and memory leak and play with the sample project.

like image 68
Dmitry Korobeinikov Avatar answered Sep 24 '22 22:09

Dmitry Korobeinikov