You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 05:00:58