ListView setAdapter后数据源变更时mItemCount更新时机疑问
问题解答
你观察到的现象和ListView的执行流程、mItemCount的更新逻辑直接相关,你在onCreate中setAdapter后立刻修改数据集的操作,发生在ListView首次布局绘制之前,setAdapter中赋值的mItemCount=5从未被实际用于渲染流程。
mItemCount的更新时机
mItemCount不是只在setAdapter时赋值一次,它会在两个核心场景被重新赋值为mAdapter.getCount()的返回值:
- 布局流程触发更新:ListView继承自AbsListView,在每次执行
onMeasure、onLayout等布局相关逻辑前,都会主动拉取适配器的最新count值更新mItemCount,以此计算自身需要的高度、需要渲染的条目总数。 - 数据集变更通知触发更新:当ListView完成首次渲染后,如果你修改了适配器绑定的数据源,调用
notifyDataSetChanged()时,适配器会向注册的DataSetObserver发送变更通知,AbsListView收到通知后会调用requestLayout()触发重绘,重绘流程中同样会重新拉取适配器count值更新mItemCount。
你的测试代码的执行逻辑
你贴的测试代码运行时的执行顺序是:
- 初始化长度为5的数组,创建适配器,调用
setAdapter,此时mItemCount被赋值为5 - 你在
onCreate的同步代码块中立刻向数组新增5个元素,数组长度变为10。这一步是主线程同步执行的,执行期间不会插入任何布局、绘制任务,所以此时ListView根本没开始渲染 onCreate方法执行完成后,主线程才会处理消息队列中等待的View树布局、绘制任务,此时调用mAdapter.getCount()拿到的是数组最新长度10,mItemCount被更新为10,最终ListView渲染全部10个元素。
注意:你这种直接修改数据源不调用
notifyDataSetChanged()的写法是不规范的。如果是在ListView已经完成首次渲染后(比如在按钮点击事件中直接修改数组、不调用通知方法),ListView不会收到数据源变更的信号,不会主动触发重布局,就会出现你最初预期的只显示旧数据的问题。
内容的提问来源于stack exchange,提问作者Mrityu
相关产品推荐
相关产品推荐

