包含在android support v7中的RecyclerView,是ListView的一种替代解决方案。然而,做工程时遇到如下现象:
在Item中存在NetCacheImageView(或者类似框架控件)时,偶尔会出现将一个条目刚刚滑动到看不见,然后将其拉回,其中的图片变为空白。
自己对照google文档写了一个异步加载图片的实现,问题依旧存在。
经过很长时间的调试,终于定位到这个问题。
Bitmap有一个recycle()方法用于内存回收。为了及时回收Bitmap的内存,减少OOM的出现,框架扩展了BitmapDrawable类,在其中实现了引用计数的机制。具体来说,扩展类维持两个计数,一个管理缓存引用,在缓存管理类中增减;另一个管理界面显示引用,问题就出在这个上面。
为了管理界面显示引用,框架扩展了ImageView中的setImageDrawable方法。在其中对旧的ImageDrawable引用计数减一,新的ImageDrawable计数加一。然后,为了在ImageView退出屏幕时及时回收Bitmap,扩展了onDetachedFromWindow方法,在其中调用setImageDrawable(null),以回收当前显示的Bitmap。至此之前我的关注点一直在图片加载的实现上,理清楚这个机制之后才考虑到是不是回收时机出了问题。
对RecyclerView进行分析之后我发现,当一个item被滑动到刚好看不见的位置时,触发了该item及其子View的onDetachedFromWindow,同样也就调用了setImageDrawable(null)。但是,RecyclerView.Adapter.onViewRecycled方法没有立刻被调用,而要等到继续滑动RecyclerView时才调用。也就是说,RecyclerView没有立即回收已经不在显示区域的item。如果此时将该item拉回,也不会再调用RecyclerView.Adapter.onBindViewHolder,也就是图片消失之后就不会再显示了,出现了开头提到的问题。
针对这个问题,我用了一个比较dirty的解决方案,扩展了RecyclerView,Adapter,并让ImageView中onDetachedFromWindow去判断上层View是否有RecyclerView,导致代码耦合比较强。
不知是否有比较好的解决方案?