RecyclerView嵌套NestedScrollView时onCreateViewHolder重复调用问题求助
嘿,我之前也踩过这个坑!先给你理清楚问题根源,再一步步说解决方案:
首先得纠正一个误区:你没法强制RecyclerView只调用一次onCreateViewHolder——ViewHolder的复用机制是基于"屏幕可见范围内的同类型item复用ViewHolder"设计的。而你现在遇到每个item都触发onCreateViewHolder的核心原因是:NestedScrollView会把RecyclerView的高度拉伸成wrap_content,导致RecyclerView一次性加载所有列表项(所有item都处于"可见"状态),复用机制直接失效,这才是卡顿的元凶。
那该怎么解决?给你几个可行的方案:
方案1:彻底抛弃NestedScrollView(最优解)
如果你的页面是「顶部固定内容 + 列表」或者「列表 + 底部固定内容」的结构,完全不需要NestedScrollView,直接用RecyclerView的Header/Footer或者ConcatAdapter来组合内容:
- 把非列表的部分做成RecyclerView的HeaderView/FooterView,和列表项一起交给RecyclerView管理
- 用ConcatAdapter把多个Adapter(比如顶部内容的Adapter、列表的Adapter)合并成一个,交给RecyclerView
这样RecyclerView可以正常复用ViewHolder,滚动流畅,彻底解决卡顿问题。
方案2:必须嵌套时的优化手段(迫不得已才用)
如果实在没法去掉NestedScrollView,那只能从优化ViewHolder创建和布局加载入手:
- 优化item布局:用
ConstraintLayout代替多层LinearLayout嵌套,减少布局层级;给布局设置android:layoutOpticalBounds="true"减少过度绘制;避免在item布局中滥用wrap_content属性(尤其是嵌套的ViewGroup) - 提前预加载布局:在Activity/Fragment初始化时,提前用LayoutInflater加载好item布局的View并缓存,在
onCreateViewHolder中直接复用这个View(注意:如果item有动态内容,要确保每次绑定数据时重置状态,避免复用混乱) - 开启RecyclerView固定尺寸:给RecyclerView设置
setHasFixedSize(true),让它不用频繁计算自身尺寸,减少布局耗时 - 异步加载布局:API 30及以上可以用
LayoutInflater.inflateAsync()异步加载item布局,避免阻塞主线程
额外提醒:关于nestedScrollingEnabled="false"
你设置的这个属性只是关闭了RecyclerView的嵌套滚动,让NestedScrollView接管滚动,但并没有解决RecyclerView一次性加载所有item的问题,所以对ViewHolder复用没有帮助。
总结一下:最好的方式是让RecyclerView回到它的本职工作——管理可复用的列表项,不要用NestedScrollView嵌套它。如果实在要嵌套,就从布局优化和预加载入手缓解卡顿,但没法实现"只调用一次onCreateViewHolder"(除非你的列表只有一个item,那另当别论)。
内容的提问来源于stack exchange,提问作者materight

