ListView的高效率使用
ListView作为android上最常用的控件之一,其原理与效率十分值得我们去探究,特别是当与Button、ImageView一起时,许多问题便纷至沓来。今天我就说说这老生常谈的话题,也是由此做一个总结。
一,ListView的原理
在Android中有一个Recycler的构件,滑出屏幕的的Item就会被缓存在里面。但并不是缓存全部,只是会根据item的类型数来缓存相应的个数。举个例子,一般情况下都没有必要去重写ListView的getViewTypeCount())函数,那么type值也就为1,也就是说,Recycler中只会缓存一个item View。如下图(图片来自网络):
当Item1滑出屏幕的时候,Recycler构件中就缓存了item1,再往上滑,item2滑出屏幕。这时有趣的事情就发生了,Recycler构件只会缓存一个item,这时毫无争议会缓存Item2,那么item1就被复用,显示为item8(实际上当item1完全滑出界面时就会被显示作Item8了)。
二,需要注意的地方
1,数据与显示分离
由于ListView的item view
是复用的,这就要求我们将数据与显示分离,否则将造成显示的结果错乱。比如,当ListView的Item
中含有单选按钮时,假如只是简单地记录按钮的点击状态,那么当滑动ListView的时候,“已点击”与“未点击”就显示混乱。再举个例子,ListView的item
中含有图片,选择异步加载。如果做法是当下载完毕后就设置ImageView的显示内容,那么也会造成混乱。
比较明智的做法是自己单独维护一个数据结构来缓存数据,上文的点击状态就时候使用ArrayList
,异步加载的图片就适合使用HashMap
。
2,数据更新
ListView的数据更新只能在UI主线程中进行,否则会报:1
“java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread.”
另外还需要注意的是,不能更改原来的数据指向的对象。比如,原来的数据List
指向的是 ArrayList1
。在数据更新后,为了方便,我们直接 List = ArrayList2
。这样就使List
指向新的ArrayList
,也是会出错的。总而言之,唯一的做法就是在原理的ArrayList1中增加或删除数据。