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

异构多视图嵌套RecyclerView:如何在主类获取内部数据并计算Int值?

嘿,我之前在做异构嵌套RecyclerView的时候也碰到过一模一样的问题——要从主类里拿内部RecyclerView的数据还得做数值计算,给你分享几个我亲测好用的方案:

一、获取内部RecyclerView数据的核心思路

因为是异构多视图的主RecyclerView,首先得区分出包含内部RecyclerView的ViewHolder类型,再针对性处理数据获取。

1. 让内部Adapter直接暴露数据获取接口

这是最直接的方式:在内部RecyclerView的Adapter里写方法,把内部数据或者你需要的数值暴露出来,然后主Adapter持有内部Adapter的实例,供主类调用。

内部Adapter示例:

public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.InnerViewHolder> {
    private List<Integer> innerDataList; // 内部数据源,比如每个Item的数值
    private Context context;

    public InnerAdapter(Context context, List<Integer> innerDataList) {
        this.context = context;
        this.innerDataList = innerDataList;
    }

    // 核心:暴露获取内部所有数据的方法
    public List<Integer> getInnerAllValues() {
        return new ArrayList<>(innerDataList); // 返回副本避免外部修改原数据
    }

    // 如果是需要获取用户输入的动态数值(比如数量输入框),可以写这个方法
    public List<Integer> getCurrentInputValues(RecyclerView innerRV) {
        List<Integer> inputValues = new ArrayList<>();
        for (int i = 0; i < getItemCount(); i++) {
            InnerViewHolder holder = (InnerViewHolder) innerRV.findViewHolderForAdapterPosition(i);
            if (holder != null) {
                // 假设每个内部Item有一个EditText用于输入数值
                String numStr = holder.etQuantity.getText().toString().trim();
                inputValues.add(TextUtils.isEmpty(numStr) ? 0 : Integer.parseInt(numStr));
            } else {
                // 如果ViewHolder被回收,直接从数据源取保存的数值
                inputValues.add(innerDataList.get(i));
            }
        }
        return inputValues;
    }

    // 省略ViewHolder、onCreateViewHolder、onBindViewHolder等基础代码
    static class InnerViewHolder extends RecyclerView.ViewHolder {
        EditText etQuantity;
        public InnerViewHolder(@NonNull View itemView) {
            super(itemView);
            etQuantity = itemView.findViewById(R.id.et_quantity);
        }
    }
}

主Adapter里持有内部Adapter实例:

在主Adapter中,用一个Map来保存每个位置对应的内部Adapter(因为是异构,只有部分ViewHolder包含内部RecyclerView):

public class MainAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    private List<MainItem> mainItemList; // 主数据源,包含多种类型的Item
    private Context context;
    private Map<Integer, InnerAdapter> innerAdapterMap = new HashMap<>(); // 保存内部Adapter实例

    // 构造方法省略

    @Override
    public int getItemViewType(int position) {
        // 返回当前Item的类型,比如0是普通文本Item,1是包含内部RecyclerView的Item
        return mainItemList.get(position).getItemType();
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        MainItem currentItem = mainItemList.get(position);
        if (getItemViewType(position) == 1) { // 判断是包含内部RecyclerView的ViewHolder
            InnerRVViewHolder innerHolder = (InnerRVViewHolder) holder;
            InnerAdapter innerAdapter = new InnerAdapter(context, currentItem.getInnerData());
            innerHolder.innerRV.setLayoutManager(new LinearLayoutManager(context));
            innerHolder.innerRV.setAdapter(innerAdapter);
            // 把内部Adapter实例存入Map,关联主Item的位置
            innerAdapterMap.put(position, innerAdapter);
        } else {
            // 处理其他类型的ViewHolder,比如普通文本、图片Item
            TextViewHolder textHolder = (TextViewHolder) holder;
            textHolder.tvContent.setText(currentItem.getContent());
        }
    }

    // 对外暴露方法,供主类(Activity/Fragment)获取所有内部数据
    public List<List<Integer>> getAllInnerData() {
        List<List<Integer>> allData = new ArrayList<>();
        for (Map.Entry<Integer, InnerAdapter> entry : innerAdapterMap.entrySet()) {
            allData.add(entry.getValue().getInnerAllValues());
        }
        return allData;
    }

    // 对外暴露获取内部输入数值的方法
    public List<List<Integer>> getAllInnerInputValues() {
        List<List<Integer>> allInputValues = new ArrayList<>();
        for (Map.Entry<Integer, InnerAdapter> entry : innerAdapterMap.entrySet()) {
            // 需要拿到对应的内部RecyclerView实例,可以在主ViewHolder里保存
            InnerRVViewHolder holder = (InnerRVViewHolder) mainRecyclerView.findViewHolderForAdapterPosition(entry.getKey());
            if (holder != null) {
                allInputValues.add(entry.getValue().getCurrentInputValues(holder.innerRV));
            }
        }
        return allInputValues;
    }

    // 省略ViewHolder定义和其他基础方法
    static class InnerRVViewHolder extends RecyclerView.ViewHolder {
        RecyclerView innerRV;
        public InnerRVViewHolder(@NonNull View itemView) {
            super(itemView);
            innerRV = itemView.findViewById(R.id.inner_rv);
        }
    }

    static class TextViewHolder extends RecyclerView.ViewHolder {
        TextView tvContent;
        public TextViewHolder(@NonNull View itemView) {
            super(itemView);
            tvContent = itemView.findViewById(R.id.tv_content);
        }
    }
}

主类(比如Activity)调用:

// 获取所有内部原始数据
List<List<Integer>> allInnerData = mainAdapter.getAllInnerData();
// 获取用户输入的所有动态数值
List<List<Integer>> allInputValues = mainAdapter.getAllInnerInputValues();

2. 用回调接口实时传递数据

如果需要实时监听内部RecyclerView的数值变化(比如用户输入数量时立刻更新总和),可以用回调接口层层传递:

内部Adapter定义回调:

public class InnerAdapter extends RecyclerView.Adapter<InnerAdapter.InnerViewHolder> {
    // 定义回调接口,传递主Item位置、内部Item位置、变化后的数值
    public interface OnInnerValueChangeListener {
        void onValueChanged(int mainItemPosition, int innerItemPosition, int newValue);
    }

    private OnInnerValueChangeListener valueChangeListener;
    private int mainItemPosition; // 保存当前内部RecyclerView对应的主Item位置

    public void setOnInnerValueChangeListener(OnInnerValueChangeListener listener, int mainPos) {
        this.valueChangeListener = listener;
        this.mainItemPosition = mainPos;
    }

    @Override
    public void onBindViewHolder(@NonNull InnerViewHolder holder, int position) {
        int currentValue = innerDataList.get(position);
        holder.etQuantity.setText(String.valueOf(currentValue));

        // 监听输入框变化,实时回调
        holder.etQuantity.addTextChangedListener(new TextWatcher() {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}

            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {}

            @Override
            public void afterTextChanged(Editable s) {
                int newValue = TextUtils.isEmpty(s.toString()) ? 0 : Integer.parseInt(s.toString());
                // 更新数据源
                innerDataList.set(position, newValue);
                // 通知上层
                if (valueChangeListener != null) {
                    valueChangeListener.onValueChanged(mainItemPosition, position, newValue);
                }
            }
        });
    }

    // 省略其他代码
}

主Adapter传递回调到主类:

public class MainAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    // 定义主类的回调接口
    public interface OnMainValueChangeListener {
        void onTotalChanged(int total);
    }

    private OnMainValueChangeListener mainValueListener;

    public void setOnMainValueChangeListener(OnMainValueChangeListener listener) {
        this.mainValueListener = listener;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (getItemViewType(position) == 1) {
            InnerRVViewHolder innerHolder = (InnerRVViewHolder) holder;
            InnerAdapter innerAdapter = new InnerAdapter(context, currentItem.getInnerData());
            // 设置内部Adapter的回调
            innerAdapter.setOnInnerValueChangeListener((mainPos, innerPos, newValue) -> {
                // 更新主数据源
                mainItemList.get(mainPos).getInnerData().set(innerPos, newValue);
                // 计算总和并通知主类
                int total = calculateTotal();
                if (mainValueListener != null) {
                    mainValueListener.onTotalChanged(total);
                }
            }, position);
            innerHolder.innerRV.setAdapter(innerAdapter);
            innerAdapterMap.put(position, innerAdapter);
        }
        // 省略其他代码
    }

    // 计算所有内部数值的总和
    private int calculateTotal() {
        int total = 0;
        for (MainItem item : mainItemList) {
            if (item.getItemType() == 1) {
                for (int num : item.getInnerData()) {
                    total += num;
                }
            }
        }
        return total;
    }
}

主Activity里监听实时总和:

mainAdapter.setOnMainValueChangeListener(total -> {
    // 实时更新UI显示总和
    tvTotal.setText("当前总和:" + total);
});
二、注意事项
  • 当内部RecyclerView的ViewHolder被回收时,findViewHolderForAdapterPosition会返回null,所以一定要把数值同步保存到数据源中,避免数据丢失。
  • 异构RecyclerView要确保getItemViewType的判断准确,避免强转ViewHolder时出现ClassCastException。
  • 如果主RecyclerView有数据刷新,记得清空并重新填充innerAdapterMap,避免引用旧的Adapter实例。

内容的提问来源于stack exchange,提问作者Ankita Singh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:37:21