Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ViewHolder not as a inner class

Can the RecyclerView.ViewHolder be used not as a inner class? Are there any issues on doing so?

I have searched around but havent found any documentation on it!

like image 278
ivoencarnacao Avatar asked Mar 16 '15 01:03

ivoencarnacao


1 Answers

Actually, I think a ViewHolder should either be a static nested class (mind the static!) or a top-level class (which actually will be no different, just the class name will contains the outer class name followed by a $ and then the inner class name).

Why do I think so? When the ViewHolder is a non-static inner class of the adapter, it keeps a reference to the adapter. Now, when you call RecyclerView.swapAdapter(newAdapter, false) (or was it true? I don't remember), the new adapter will use the ViewHolders created previously by the old one. As it is impossible to null/clear such an implicit reference in these holders, this reference to the first adapter has leaked and cannot be garbage collected. This is bad enough.

But, in my case, I had real issues not related to memory. My adapter had a 'selection model' which kept position-to-data mapping and the view holder would use the data when it shown the item (like for instance, when the selection model said the item at position 17 is selected, when it was drawn on screen, its font color would change) to mark it for the user. It did it by just accessing the selection model field from the adapter, which in Java means it uses the implicit reference to the enclosing adapter instance and than accesses its field. Now, after swapAdapter, the preserved ViewHolders were still using the selection model of the old adapter, and the UI was broken, as some items would show up as selected whereas in the new model they were not.

Essentially, it is impossible for such non-static inner class holders who outlive the adapter that created them and are used by another one to really forget the old and use the new adapter, as there is no way to clear that implicit reference.

There are many solutions to this, one of which is for the ViewHolder to be a static nested class, and just give it a reference to the adapter explicitly when it binds, and null it when it unbinds. I have been using a top-level classes for my view holders with explicit references to the adapter, which I think it what you are asking about. Mind that very often the holders don't need any reference to their adapter at all so you might not need to set the adapter at all.

Of course, my issue stemmed from the fact that I swapped the cursor; if you don't do it, you probably won't ever notice any problems, but I think it is best to be aware of them.

like image 154
wujek Avatar answered Oct 02 '22 12:10

wujek