RecyclerView加载10条/铺满屏幕时onScrolled未检测滚动的分页问题
RecyclerView分页异常排查与解决
问题现象
- 当分页加载恰好10条数据(或数据刚好铺满屏幕)时,RecyclerView的滚动无法被
addOnScrollListener的onScrolled方法检测到,分页加载不触发; - 选择加载25/50条数据时,分页功能正常;
- 调试确认:滚动到底部时仅进入
onScrollStateChanged方法,未进入onScrolled。
现有代码
RecyclerView初始化代码
VulnerabilityScanAdapter vulnerabilityScanAdapter = new VulnerabilityScanAdapter( getActivity(), callback, vulnerabilityScanPojoList ); vulnerabilityScanAdapter.notifyDataSetChanged(); final LinearLayoutManager mLayoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); vulnerabilityScanRv.setLayoutManager(mLayoutManager); vulnerabilityScanRv.setItemAnimator(new DefaultItemAnimator()); vulnerabilityScanRv.setAdapter(vulnerabilityScanAdapter);
分页监听代码
vulnerabilityScanRv.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); } @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if(dy > 0){ // Scrolling Down if (totalCount > currentPageCount) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (linearLayoutManager != null && linearLayoutManager.findLastCompletelyVisibleItemPosition() == vulnerabilityScanPojoList.size() - 1) { //bottom of list! loadMore(); } } else { //showSnackForAttributes(true,"No more data avaiable."); } }else if(dy < 0){ // Scrolling Up } } });
问题根源
当RecyclerView的内容高度刚好等于或略小于屏幕高度时,用户的滚动操作不会产生实际的滚动位移(dy=0),因此RecyclerView不会调用onScrolled方法。此时滚动动作只会触发onScrollStateChanged,但你的分页逻辑完全依赖onScrolled中的dy>0判断,导致加载更多无法触发。
解决方案
方案1:在onScrollStateChanged中补充底部判断
利用滚动状态变为空闲的时机,检查是否已到达列表底部,触发加载:
// 添加全局标记防止重复请求 private boolean isLoading = false; @Override public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) { super.onScrollStateChanged(recyclerView, newState); // 滚动停止时检查是否到达底部 if (newState == RecyclerView.SCROLL_STATE_IDLE && !isLoading) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (linearLayoutManager != null && totalCount > currentPageCount) { int lastVisiblePos = linearLayoutManager.findLastCompletelyVisibleItemPosition(); if (lastVisiblePos == vulnerabilityScanPojoList.size() - 1) { isLoading = true; loadMore(); } } } } // 记得在loadMore请求完成后重置isLoading private void loadMore() { // 发起请求逻辑... // 请求成功/失败后: // isLoading = false; }
方案2:修改onScrolled的触发逻辑
移除dy>0的限制,同时加入防重复标记,只要到达底部就触发加载:
private boolean isLoading = false; @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); if (totalCount > currentPageCount && !isLoading) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (linearLayoutManager != null) { int lastVisiblePos = linearLayoutManager.findLastCompletelyVisibleItemPosition(); if (lastVisiblePos == vulnerabilityScanPojoList.size() - 1) { isLoading = true; loadMore(); } } } }
方案3:确保内容可滚动
给RecyclerView添加最小高度,或在列表末尾添加占位Item,让内容高度略大于屏幕高度,保证滚动位移产生:
<!-- 在布局文件中给RecyclerView设置最小高度 --> <androidx.recyclerview.widget.RecyclerView android:id="@+id/vulnerabilityScanRv" android:layout_width="match_parent" android:layout_height="match_parent" android:minHeight="1dp"/>
或在Adapter中动态添加占位项:
@Override public int getItemCount() { // 如果列表数量刚好是10,添加一个占位项 return vulnerabilityScanPojoList.size() == 10 ? vulnerabilityScanPojoList.size() + 1 : vulnerabilityScanPojoList.size(); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { if (position == vulnerabilityScanPojoList.size()) { // 绑定占位项,设置透明或隐藏 holder.itemView.setVisibility(View.INVISIBLE); } else { // 正常绑定数据 } }
额外优化建议
- 用
findLastVisibleItemPosition替代findLastCompletelyVisibleItemPosition,当最后一项部分可见时就触发加载,提升用户体验; - 所有加载逻辑必须加入
isLoading控制,避免重复发起网络请求。
内容的提问来源于stack exchange,提问作者nikb727
相关产品推荐
相关产品推荐

