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

如何为使用StaggeredGridLayoutManager的RecyclerView实现无限滚动分页

修复方案

1. 无限滚动逻辑修正

你当前的滚动监听逻辑判断条件错误,StaggeredGridLayoutManager需要判断最后一个可见item的位置而非第一个,同时需要添加上滑判断避免误触发,修改后的滚动监听代码如下:

postRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
        super.onScrolled(recyclerView, dx, dy);
        visibleItemCount = staggeredGridLayoutManager.getChildCount();
        totalItemCount = staggeredGridLayoutManager.getItemCount();
        int[] lastVisibleItems = staggeredGridLayoutManager.findLastVisibleItemPositions(null);
        // 取所有列最后可见item的最大值作为判断依据
        int lastVisibleItemPosition = Arrays.stream(lastVisibleItems).max().getAsInt();

        // dy>0代表上滑操作,且剩余2个item时提前触发加载,可自行调整阈值
        if (loading && dy > 0 && (lastVisibleItemPosition + 2) >= totalItemCount && !isLoadMoreEnd) {
            loading = false;
            getData();
            Log.d("tag", "LOAD NEXT ITEM");
        }
    }
});

新增全局变量private boolean isLoadMoreEnd = false; 用于标记是否已加载完全部数据,避免无意义的重复请求。

2. 分页加载逻辑修正

你当前getData()方法存在两个核心问题:一是每次请求都会清空已有列表,导致加载更多后之前的内容消失;二是每次拉取全量数据,没有实现分页逻辑。
修改为Firebase Realtime Database分页加载的代码如下:

// 新增全局变量
private String lastLoadedKey = null;
private static final int PAGE_SIZE = 15; // 每页加载数量可自行调整

private void getData() {
    Query query;
    if (lastLoadedKey == null) {
        // 首次加载
        query = databaseReference.orderByKey().limitToLast(PAGE_SIZE);
    } else {
        // 分页加载,从上次加载的最后一个key开始拉取
        query = databaseReference.orderByKey().endAt(lastLoadedKey).limitToLast(PAGE_SIZE + 1);
    }

    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            progressBar.setVisibility(View.GONE);
            postRecyclerView.setVisibility(View.VISIBLE);
            List<Upload> newUploads = new ArrayList<>();
            for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                Upload upload = dataSnapshot.getValue(Upload.class);
                Objects.requireNonNull(upload).setmKey(dataSnapshot.getKey());
                newUploads.add(upload);
            }

            // 去掉重复的边界key
            if (lastLoadedKey != null && newUploads.size() > 0) {
                newUploads.remove(0);
            }

            if (newUploads.size() == 0) {
                isLoadMoreEnd = true;
                loading = true;
                return;
            }

            // 记录本次加载的最后一个key
            lastLoadedKey = newUploads.get(newUploads.size() - 1).getmKey();
            // 追加数据而非清空原有数据
            mUploads.addAll(newUploads);
            // 局部更新代替全局刷新,性能更好
            postsAdapter.notifyItemRangeInserted(mUploads.size() - newUploads.size(), newUploads.size());
            loading = true;
        }

        @Override
        public void onCancelled(@NonNull DatabaseError error) {
            loading = true;
        }
    });
}

同时在onCreateView中适配器初始化完成后补上首次getData()调用,你当前的代码缺少首次触发加载数据的逻辑。

3. 图片不加载问题修复

你Glide配置同时使用了centerCrop和fitCenter,两个缩放配置冲突,删掉其中一个即可;另外检查Upload类的getmImageUrl()方法返回值是否正确,可添加日志打印验证。修改后的Glide加载代码:

Glide.with(mcontext)
        .load(uploadCurrent.getmImageUrl())
        .diskCacheStrategy(DiskCacheStrategy.AUTOMATIC)
        .placeholder(shimmerDrawable)
        .centerCrop() // 保留需要的缩放模式即可
        .into(holder.imageView);

另外删掉PostAdapter中mUploads的static修饰符,静态变量会导致内存泄漏,修改为:

public List<Upload> mUploads;

4. 其他补充

如果需要实时监听数据库内容更新,可单独设置全局的addValueEventListener处理数据新增/删除/修改逻辑,不要和分页加载逻辑混用。

内容的提问来源于stack exchange,提问作者Vasant Raval

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 18:57:02