Android RecyclerView Gotchas
Published Spring, 2019
RecyclerView’s have a bad habit of “blinking” when they update. Basically, it happens when the view refreshes its images. They briefly disappear and reappear which looks like a “blink”. To prevent this, you set the
setHasStableIds value to true on the
RecyclerViewAdapter. Then you override the
getItemId() method in the adapter and ensure that it always returns the same value for each ID. A simple way to accomplish this is to use the element’s hash code. Here is a blog post on Medium.com which explains the problem and the fix.
Another quirk of RecyclerViewAdapters is that they sometimes crash when the user selects an item during a refresh. The reason is that the
getAdapterPosition() method from the
ViewHolder returns a value of -1 if the view is currently refreshing. If you are planning to use this value to reference an element in an array, it will throw an
ArrayIndexOutOfBoundsException. In the distant past, we used to employ the getPosition() method. But that method has been deprecated. Unfortunately, the replacement method, getAdapterPosition() doesn’t…you know…work. One solution is to check the result of the
getAdapterPosition() method against
RecyclerView.NO_POSITION (which is -1) before using the value returned by
But what if you actually need the value right now and can’t just bypass it? In that case, you can use getLayoutPosition() instead. I’ve done a fair amount of testing with getLayoutPosition() and I can confirm that it is far more reliable than getAdapterPosition(). That said, no solution is perfect. And if your layout is influx, you may still get burned.
Another option is reduce the amount of time required for refreshing the RecyclerView. Instead of using notifyDataSetChanged(), which refreshes the entire view, try using a slick, cool class called DiffUtils which allows you to only update the child elements that have changed. Again, this is not perfect. But reducing the time that the app spends recreating the RecyclerView makes it that much less likely that the position will be -1.