You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 14:45:39