异构多视图嵌套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
相关产品推荐
相关产品推荐

