Android实现类Reddit嵌套RecyclerView:子评论全显示在最后父评论问题
问题分析
你的核心问题是所有父评论项共用了同一个子评论数据集:适配器中的list2和listKey2是类成员变量,每次调用onBindViewHolder时,都会往同一个集合里添加子评论数据,最终所有子评论都累积到这个集合中。再加上RecyclerView的视图复用机制,最后一个父评论项会显示所有累积的子评论。
修复方案
1. 为每个父评论项创建独立的子数据集
把list2、listKey2、子适配器实例从类成员移到onBindViewHolder方法内部,让每个父评论项拥有专属的子评论集合和适配器。
2. 加载子评论前清空数据集
在Firebase的onDataChange回调中先清空当前项的子评论集合,避免重复添加旧数据。
3. 优化监听避免内存泄漏
在视图被回收时移除Firebase的监听,防止内存泄漏。
修改后的代码示例
public class commentsAdapter extends RecyclerView.Adapter<commentsAdapter.MyHolder> { ArrayList<commentsModel> list; ArrayList<commentsModel> listKey; Context context; private RecyclerView.RecycledViewPool viewPool = new RecyclerView.RecycledViewPool(); FirebaseDatabase mDatabase; public commentsAdapter(ArrayList<commentsModel> list, ArrayList<commentsModel> listKey, Context context) { this.list = list; this.listKey = listKey; this.context = context; mDatabase = FirebaseDatabase.getInstance(); // 全局初始化一次即可 } @NonNull @Override public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sample_comment, parent, false); return new MyHolder(view); } @Override public void onBindViewHolder(@NonNull MyHolder holder, int position) { commentsModel adp = list.get(position); commentsModel adp2 = listKey.get(position); holder.profileName.setText(adp.getName()); holder.points.setText(adp.getPoints()); holder.postedTime.setText(adp.getTime()); Glide.with(context).load(adp.getImg()).into(holder.profileImg); // 为当前父评论创建独立的子评论数据集 ArrayList<commentsModel> list2 = new ArrayList<>(); ArrayList<commentsModel> listKey2 = new ArrayList<>(); commentsAdapter adapter = new commentsAdapter(list2, listKey2, context); // 注意:Reddit式嵌套评论应该用垂直布局,这里修改为VERTICAL(根据需求调整) LinearLayoutManager layoutManager = new LinearLayoutManager( holder.innerRes.getContext(), LinearLayoutManager.VERTICAL, false); holder.innerRes.setLayoutManager(layoutManager); holder.innerRes.setHasFixedSize(true); holder.innerRes.setRecycledViewPool(viewPool); holder.innerRes.setAdapter(adapter); String path = adp2.getPath(); // 保存监听引用,方便后续移除 ValueEventListener listener = new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { // 先清空数据集,避免重复加载旧数据 list2.clear(); listKey2.clear(); for (DataSnapshot snapshot1 : snapshot.getChildren()) { commentsModel adpChild = snapshot1.getValue(commentsModel.class); list2.add(adpChild); String path2 = snapshot1.getKey(); String fullPath = path + "/" + path2 + "/Comments"; commentsModel adpKeyChild = new commentsModel(fullPath); listKey2.add(adpKeyChild); } adapter.notifyDataSetChanged(); } @Override public void onCancelled(@NonNull DatabaseError error) { // 可添加错误处理逻辑 } }; DatabaseReference ref = mDatabase.getReference().child(path); ref.addValueEventListener(listener); // 将监听和引用绑定到ViewHolder,方便回收时清理 holder.listener = listener; holder.reference = ref; } @Override public void onViewRecycled(@NonNull MyHolder holder) { super.onViewRecycled(holder); // 移除监听,防止内存泄漏 if (holder.reference != null && holder.listener != null) { holder.reference.removeEventListener(holder.listener); } } @Override public int getItemCount() { return list.size(); } public class MyHolder extends RecyclerView.ViewHolder { TextView profileName, postedTime, points; ShapeableImageView profileImg; RecyclerView innerRes; // 新增变量保存监听和数据库引用 ValueEventListener listener; DatabaseReference reference; public MyHolder(@NonNull View itemView) { super(itemView); profileName = itemView.findViewById(R.id.profileName); postedTime = itemView.findViewById(R.id.postedTime); profileImg = itemView.findViewById(R.id.profileImg); points = itemView.findViewById(R.id.points); innerRes = itemView.findViewById(R.id.innerRec); } } }
额外说明
- 子RecyclerView布局方向:原代码用了
HORIZONTAL,如果是类似Reddit的垂直嵌套评论,建议改成LinearLayoutManager.VERTICAL。 - Firebase监听选择:如果不需要实时更新子评论,可以把
addValueEventListener改成addListenerForSingleValueEvent,减少监听开销。
内容的提问来源于stack exchange,提问作者GajjarSVNIT
相关产品推荐
相关产品推荐

