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

如何向Firebase发送分页请求实现RecyclerView无限滚动效果

解决方案

现有问题说明

  1. 每次调用getData()都会拉取全量500条数据,没有做分页查询
  2. 数据回调后直接清空mUploads列表再重新添加所有数据,没有累加新页数据
  3. 初始化顺序错误:先调用getData()再初始化mUploads和适配器,首次加载可能出现空指针
  4. 适配器的mUploads被声明为static,容易引发内存泄漏和多实例数据冲突

修改步骤

1. 修正PostAdapter_Home的静态成员问题

将mUploads改为私有非静态成员:

public class PostAdapter_Home extends RecyclerView.Adapter<PostAdapter_Home.PostViewHolder> {
    // 去掉static修饰符
    private List<Upload> mUploads;
    public Context mcontext;
    // 其余代码保持不变
}

2. 给Home_Fragment添加分页相关全局变量

private boolean loading = true;
private int pastVisibleItems, visibleItemCount, totalItemCount;
// 新增分页变量
private static final int PAGE_SIZE = 10;
private String lastLoadedKey = null;
private boolean isLastPage = false;

3. 调整onCreateView的初始化顺序

把mUploads和适配器的初始化逻辑移到getData()之前:

@SuppressLint("SourceLockedOrientationActivity")
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_home, container, false);
    requireActivity().setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    MaterialToolbar materialToolbar = view.findViewById(R.id.toolbar);
    materialToolbar.setOnMenuItemClickListener(toolbarItemClickListener);
    postRecyclerView = view.findViewById(R.id.recyclerViewHome);
    shimmerFrameLayout = view.findViewById(R.id.shimmerEffect);

    StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(1, StaggeredGridLayoutManager.VERTICAL);
    postRecyclerView.setLayoutManager(staggeredGridLayoutManager);

    // 移到这里初始化
    shimmerFrameLayout.startShimmer();
    mUploads = new ArrayList<>();
    postsAdapter = new PostAdapter_Home(getContext(), mUploads);
    postRecyclerView.setAdapter(postsAdapter);

    // 初始化完成再加载数据
    getData();

    postRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
        @Override
        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
            visibleItemCount = staggeredGridLayoutManager.getChildCount();
            totalItemCount = staggeredGridLayoutManager.getItemCount();
            int[] firstVisibleItems = staggeredGridLayoutManager.findFirstVisibleItemPositions(null);
            if (firstVisibleItems != null && firstVisibleItems.length > 0) {
                pastVisibleItems = firstVisibleItems[0];
            }
            // 新增最后一页判断
            if (loading && !isLastPage) {
                if ((visibleItemCount + pastVisibleItems) >= totalItemCount) {
                    loading = false;
                    getData();
                    Log.d("tag", "LOAD NEXT ITEM");
                }
            }
        }
    });

    postRecyclerView.scrollToPosition(Home_Fragment.saved_position);
    return view;
}

4. 重写getData()实现Firebase分页查询

private void getData() {
    Query query;
    if (lastLoadedKey == null) {
        // 首次加载,查前PAGE_SIZE条
        query = databaseReference.orderByKey().limitToFirst(PAGE_SIZE);
    } else {
        // 加载下一页,从lastLoadedKey开始查PAGE_SIZE+1条,多查1条用来判断是否到最后一页
        query = databaseReference.orderByKey().startAt(lastLoadedKey).limitToFirst(PAGE_SIZE + 1);
    }
    // 用单次事件监听,避免数据变动重复触发
    query.addListenerForSingleValueEvent(new ValueEventListener() {
        @SuppressLint("NotifyDataSetChanged")
        @Override
        public void onDataChange(@NonNull DataSnapshot snapshot) {
            if (snapshot.exists()) {
                if (lastLoadedKey == null) {
                    // 首次加载隐藏shimmer
                    shimmerFrameLayout.stopShimmer();
                    shimmerFrameLayout.setVisibility(View.GONE);
                    postRecyclerView.setVisibility(View.VISIBLE);
                }
                List<Upload> pageList = new ArrayList<>();
                for (DataSnapshot dataSnapshot : snapshot.getChildren()) {
                    Upload upload = dataSnapshot.getValue(Upload.class);
                    assert upload != null;
                    upload.setmKey(dataSnapshot.getKey());
                    pageList.add(upload);
                }
                // 非首次加载要去掉重复的第一条(就是上一页最后一条)
                if (lastLoadedKey != null && pageList.size() > 0) {
                    pageList.remove(0);
                }
                // 累加新页数据
                mUploads.addAll(pageList);
                postsAdapter.notifyDataSetChanged();

                // 判断是否还有下一页
                if (pageList.size() == PAGE_SIZE) {
                    // 还有下一页,记录最后一条的key
                    lastLoadedKey = mUploads.get(mUploads.size() - 1).getmKey();
                } else {
                    // 没有更多数据
                    isLastPage = true;
                }
            } else {
                // 没有数据直接标记最后一页
                isLastPage = true;
            }
            loading = true;
        }

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

内容的提问来源于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.28 13:06:04