如何为使用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
相关产品推荐
相关产品推荐

