在List Adapter中需检查现有视图吗?附Expandable List Adapter代码
在Expandable List Adapter中检查现有视图的必要性
当然有必要!这是Android列表组件优化性能的核心操作之一,咱们来掰扯清楚为什么:
核心原因:视图复用机制
Android的ExpandableListView(包括普通ListView)为了避免大量创建视图导致内存过载、滚动卡顿,会回收滑出屏幕的视图,用来重新填充新滑入屏幕的条目内容。检查view == null就是为了判断当前是否有可复用的视图:
- 当
view == null时,说明没有可复用的视图,这时候才需要通过LayoutInflater加载布局文件,创建ViewHolder并绑定布局里的控件,最后用view.setTag(holder)把ViewHolder和视图绑定在一起; - 当
view != null时,直接通过holder = (ViewHolder) view.getTag()取出之前绑定的ViewHolder,就能直接复用已有的控件引用,不用再重复执行findViewById和布局加载,大幅节省时间和内存。
不做检查的后果
如果跳过这个检查,每次都直接inflate新布局、创建新ViewHolder,会导致:
- 内存占用飙升:比如列表有100条数据,屏幕只能显示10条,不复用的话会创建100个视图实例,而复用只需要10-12个;
- 滚动卡顿:频繁的布局加载和对象创建会让列表滚动时出现明显掉帧,用户体验极差。
结合你的代码来看
你给出的代码片段是完全正确的ViewHolder+视图复用的实现方式:
if (view == null) { view = LayoutInflater.from(mContext).inflate(R.layout.trigger_list_item, null); holder = new ViewHolder(); holder.mTrigger = trigger; holder.triggerName = view.findViewById(R.id.triggerName); holder.upButton = view.findViewById(R.id.mTriggerButtonUp); holder.downButton = view.findViewById(R.id.mTriggerButtonDown); holder.total = view.findViewById(R.id.triggerCounter); view.setTag(holder); } else { holder = (ViewHolder) view.getTag(); // 这里记得更新holder里的mTrigger等数据,避免复用旧数据哦 }
唯一要注意的是,在复用ViewHolder的时候,一定要把新条目的数据更新到ViewHolder对应的控件里,不然会出现旧数据残留的问题(比如滑到下面的条目却显示上面条目的内容)。
内容的提问来源于stack exchange,提问作者Paxana Non Grata
相关产品推荐
相关产品推荐

