Java Android 调用readRandPosts()时列表未填充致首页帖子不加载
问题根因
代码存在3个核心问题,直接导致首次进入首页无内容:
- 初始化顺序混乱:你在
postAdapter还没实例化、postLists还没初始化的时候,就第一次调用recyclerView.setAdapter(postAdapter)传了空值,属于无效绑定。 - 异步时序错误:Firebase数据库请求是多层异步执行逻辑,你在外层
Video_Posts节点的onDataChange回调里遍历帖子时,又为每个帖子发起了嵌套的关注关系查询,但循环刚跑完、嵌套查询还没返回结果往列表里塞数据,你就直接调用了postAdapter.notifyDataSetChanged(),此时列表是空的,自然渲染不出内容。点击Random按钮能看到内容,是因为点击时距离首次发起请求已经过了一段时间,嵌套的查询已经返回、数据已经缓存到列表里,第二次触发回调时就能正常渲染。 - 内存泄漏隐患:每次调用
readRandPosts()都会新增一个永久存在的ValueEventListener,从未做移除处理,反复点击按钮会重复触发回调,导致数据重复加载。
修复步骤
1. 理顺初始化逻辑
删掉onCreateView里的无效代码,调整初始化顺序,修正后这部分代码如下:
@Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_home, container, false); // 删掉这两行无意义的废代码:在当前Fragment里新建HomeFragment实例没有任何作用 // HomeFragment homeFragment = new HomeFragment(); // homeFragment.post = post; //////////////////////////// recycler view ////////////////////////////// recyclerView = (VideoPlayerRecyclerView) view.findViewById(R.id.recyclerview); LinearLayoutManager layoutManager = new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false); recyclerView.setLayoutManager(layoutManager); VerticalSpacingItemDecorator itemDecorator = new VerticalSpacingItemDecorator(0); recyclerView.addItemDecoration(itemDecorator); // 先初始化列表、适配器,再绑定给RecyclerView,删掉之前重复的setAdapter逻辑 postLists = new ArrayList<>(); postAdapter = new PostAdapter(getContext(), postLists); recyclerView.setAdapter(postAdapter); progressBar = view.findViewById(R.id.progress_circular); followingBtn = view.findViewById(R.id.followingBtn); randomBtn = view.findViewById(R.id.randomBtn); followingBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { checkFollowing(); Toast.makeText(getContext(), "Following", Toast.LENGTH_SHORT).show(); } }); randomBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { readRandPosts(); } }); readRandPosts(); // 删掉postLists != null的无效判断:你已经手动把postLists初始化成ArrayList,永远不会为null return view; }
2. 修复异步回调时序问题
把嵌套的持续监听改成单次查询,加计数器等所有帖子的关注状态都查询完成、数据全部加入列表后,再刷新UI。同时把监听抽成成员变量方便后续移除,修正后的readRandPosts相关代码:
// 把帖子监听抽成成员变量,避免重复添加 private ValueEventListener postValueEventListener; private void readRandPosts() { progressBar.setVisibility(View.VISIBLE); DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Video_Posts"); FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser(); if (user == null) { progressBar.setVisibility(View.GONE); Toast.makeText(getContext(), "用户未登录", Toast.LENGTH_SHORT).show(); return; } // 先移除旧监听,避免重复回调 if (postValueEventListener != null) { reference.removeEventListener(postValueEventListener); } postValueEventListener = new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot dataSnapshot) { postLists.clear(); long totalPostCount = dataSnapshot.getChildrenCount(); // 计数器记录已完成关注查询的帖子数 final long[] processedCount = {0}; for (DataSnapshot snapshot : dataSnapshot.getChildren()) { Post post = snapshot.getValue(Post.class); if (post == null) { processedCount[0]++; checkAndRefresh(processedCount[0], totalPostCount); continue; } DatabaseReference followRef = FirebaseDatabase.getInstance().getReference("Follow") .child(post.getPublisher()) .child("followers") .child(user.getUid()); // 用单次查询替代持续监听,避免内存泄漏 followRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot followSnapshot) { if (!followSnapshot.exists()) { postLists.add(post); } processedCount[0]++; checkAndRefresh(processedCount[0], totalPostCount); } @Override public void onCancelled(@NonNull DatabaseError error) { processedCount[0]++; checkAndRefresh(processedCount[0], totalPostCount); } }); } } @Override public void onCancelled(@NonNull DatabaseError error) { progressBar.setVisibility(View.GONE); } }; reference.addValueEventListener(postValueEventListener); } // 抽公共方法:所有帖子处理完成后再刷新列表 private void checkAndRefresh(long processed, long total) { if (processed == total) { Collections.shuffle(postLists); postAdapter.notifyDataSetChanged(); progressBar.setVisibility(View.GONE); } }
3. 补上生命周期监听移除逻辑
在Fragment销毁视图时移除数据库监听,避免内存泄漏和后台空指针:
@Override public void onDestroyView() { super.onDestroyView(); if (postValueEventListener != null) { DatabaseReference reference = FirebaseDatabase.getInstance().getReference("Video_Posts"); reference.removeEventListener(postValueEventListener); } }
额外优化提示
删掉原来嵌套查询里的"Nothing to show"Toast,否则列表加载过程中只要遇到已关注用户的帖子就会弹提示,影响使用体验。
内容的提问来源于stack exchange,提问作者user13477176
相关产品推荐
相关产品推荐

