RecyclerView滚动监听异常:未滚动却自动连续加载Firebase数据
解决RecyclerView自动连续加载更多的问题
从你的Logcat和代码来看,问题出在数据更新后RecyclerView重布局触发滚动监听,再加上Loading状态的设置时机不对,导致每次数据加载完成后,立刻又触发下一次加载,形成了循环。下面是具体的修复步骤:
1. 修正初始加载的Loading状态与数据更新逻辑
你在firstEventListener的onChildAdded里每次添加子项都设置Loading = true,这会干扰初始加载的状态管理。应该把数据更新的通知统一放在加载完成后,并且只在初始加载开始和结束时设置Loading:
// 初始化首次数据拉取的函数 private void firstEventListener() { Loading = true; // 初始加载开始时标记为加载中 Log.d(TAG, "onCreateView - Loading = " + Loading); FirebaseDatabase.getInstance().getReference().child("blogs").addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { mTotalChildren = dataSnapshot.getChildrenCount(); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { } }); final Query BlogQuery = FirebaseDatabase.getInstance().getReference().child("blogs").orderByChild("createdAt").limitToLast(3); childEventListenerMain = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot ds, String s) { Log.d(TAG, "First get blogs instance"); BlogObject addblog = ds.getValue(BlogObject.class); if (addblog != null) { // 简化对象创建,直接复用已获取的对象 BlogObject addBlog = new BlogObject( addblog.getImage(), addblog.getTitle(), addblog.getTimeStamp(), addblog.getCreatedAt() ); blogArray.add(addBlog); mLastKey = blogArray.get(0).getCreatedAt(); } } // 其他ChildEventListener方法保持不变 }; BlogQuery.addChildEventListener(childEventListenerMain); ValueEventListener BlogChildSingleListener = new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { rvaVertical.notifyDataSetChanged(); // 所有初始数据加载完成后统一更新列表 rvVertical.scrollToPosition(blogArray.size() - 1); Loading = false; // 初始加载完成,标记为可加载状态 Log.d(TAG, "Initial load completed - Loading = " + Loading); } @Override public void onCancelled(@NonNull DatabaseError databaseError) { Loading = false; // 加载失败也要恢复状态,避免卡死 } }; BlogQuery.addListenerForSingleValueEvent(BlogChildSingleListener); }
2. 优化滚动监听的触发条件
原来的滚动监听没有区分“用户主动向下滚动”和“数据更新导致的滚动”,而且Loading的标记时机太晚。我们增加**向下滚动(dy>0)**的判断,并且在触发加载前立刻标记Loading = true:
private void addOnScrollListener() { rvVertical.addOnScrollListener(new RecyclerView.OnScrollListener() { @Override public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) { super.onScrolled(recyclerView, dx, dy); Log.d(TAG, "Just Entered onScrolled and Loading = " + Loading); // 只在以下条件满足时触发加载: // 1. 用户向下滚动(dy>0) // 2. 未处于加载状态 // 3. 已经滚动到列表底部(无法再向下滚动) if (dy > 0 && !Loading && !rvVertical.canScrollVertically(1)) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) recyclerView.getLayoutManager(); if (linearLayoutManager != null && blogArray.size() >= 3 && linearLayoutManager.findLastCompletelyVisibleItemPosition() == blogArray.size() - 1 && blogArray.size() < mTotalChildren) { Loading = true; // 立刻标记为加载中,防止重复触发 getMoreBlogs(); Log.d(TAG, "Right After getMoreBlogs gets called. Loading = " + Loading); } } } }); }
3. 修复加载更多的逻辑与重复数据问题
你原来的getMoreBlogs里用endAt(mLastKey)会获取到之前的最后一条数据,导致重复。另外,不要在onChildAdded里设置Loading,而是在函数开头就标记,并且在加载完成后统一恢复状态:
public void getMoreBlogs() { Loading = true; // 加载开始时标记为加载中 tempList.clear(); // 用endAt(mLastKey - 1)避免获取重复的最后一条数据 Query getMoreQuery = FirebaseDatabase.getInstance().getReference().child("blogs") .orderByChild("createdAt") .endAt(mLastKey - 1) .limitToLast(3); childEventListenerPager = new ChildEventListener() { @Override public void onChildAdded(DataSnapshot ds, String s) { BlogObject blogObject = ds.getValue(BlogObject.class); if (blogObject != null) { BlogObject addBlog = new BlogObject( blogObject.getImage(), blogObject.getTitle(), blogObject.getTimeStamp(), blogObject.getCreatedAt() ); tempList.add(addBlog); } } // 其他ChildEventListener方法保持不变 }; getMoreQuery.addChildEventListener(childEventListenerPager); ValueEventListener addtoAdapter = new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { if (!tempList.isEmpty()) { // 只有获取到新数据时才更新列表 blogArray.addAll(0, tempList); mLastKey = blogArray.get(0).getCreatedAt(); rvaVertical.notifyDataSetChanged(); } Loading = false; // 加载完成,恢复可加载状态 Log.d(TAG, "More load completed - Loading = " + Loading); } @Override public void onCancelled(DatabaseError databaseError) { Loading = false; // 加载取消/失败也要恢复状态 } }; getMoreQuery.addListenerForSingleValueEvent(addtoAdapter); }
额外提醒:清理Firebase监听避免内存泄漏
记得在页面销毁时移除Firebase的监听,防止内存泄漏:
@Override public void onDestroyView() { super.onDestroyView(); if (childEventListenerMain != null) { FirebaseDatabase.getInstance().getReference().child("blogs").removeEventListener(childEventListenerMain); } if (childEventListenerPager != null) { FirebaseDatabase.getInstance().getReference().child("blogs").removeEventListener(childEventListenerPager); } }
这些修改应该能解决你遇到的自动连续加载问题,只有当用户主动滚动到底部时才会触发一次加载更多的逻辑。
内容的提问来源于stack exchange,提问作者Ed Delacruz
相关产品推荐
相关产品推荐

