如何向Firebase发送分页请求实现RecyclerView无限滚动效果
解决方案
现有问题说明
- 每次调用
getData()都会拉取全量500条数据,没有做分页查询 - 数据回调后直接清空
mUploads列表再重新添加所有数据,没有累加新页数据 - 初始化顺序错误:先调用
getData()再初始化mUploads和适配器,首次加载可能出现空指针 - 适配器的
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
相关产品推荐
相关产品推荐

