嵌套RecyclerView展开异常:滚动时未操作项自动展开问题排查
问题根源与解决方案
这是RecyclerView的ViewHolder复用机制导致的问题:你当前把「展开/收起」的状态直接存在ViewHolder的View控件里,当RecyclerView滚动时,已回收的ViewHolder会被复用给新的列表项,之前的展开状态就会被带到新的item上。而且你没有把展开状态和数据模型绑定,每次绑定ViewHolder时无法恢复对应国家的正确状态。
具体修复步骤
1. 给数据模型添加展开状态字段
修改你的CountryList类,新增一个布尔字段来记录当前国家的展开状态:
public class CountryList { // 原有字段 private String country; private List<String> citiesList; // 新增展开状态标记 private boolean isExpanded; // 对应的Getter/Setter public boolean isExpanded() { return isExpanded; } public void setExpanded(boolean expanded) { isExpanded = expanded; } // 原有构造方法、其他Getter/Setter保持不变 }
2. 修改Adapter的绑定逻辑
在onBindViewHolder中,根据数据模型的isExpanded状态设置城市列表的可见性,同时点击事件要更新数据状态并刷新当前item:
@Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { CountryList countryList = countryArrayList.get(position); holder.binding.countryName.setText(countryList.getCountry()); // 绑定城市列表(这里可以优化,避免每次新建Adapter,后面会说) CityRvAdapter cityRvAdapter = new CityRvAdapter(countryList.getCitiesList()); holder.binding.cityListRv.setAdapter(cityRvAdapter); // 关键:根据数据模型的状态设置可见性,而不是依赖ViewHolder缓存的状态 holder.binding.cityListRv.setVisibility(countryList.isExpanded() ? View.VISIBLE : View.GONE); holder.binding.expandCountryButton.setOnClickListener(view -> { // 更新数据模型的展开状态 boolean newState = !countryList.isExpanded(); countryList.setExpanded(newState); // 刷新当前item,确保界面和数据一致 notifyItemChanged(position); }); }
3. (可选)优化Adapter创建性能
每次onBindViewHolder都新建CityRvAdapter会造成不必要的性能损耗,可以把Adapter缓存到ViewHolder中,只更新数据:
- 先给
CityRvAdapter添加更新数据的方法:
public class CityRvAdapter extends RecyclerView.Adapter<CityRvAdapter.ViewHolder> { private List<String> cities; public CityRvAdapter(List<String> cities) { this.cities = cities; } // 新增更新数据的方法 public void updateCities(List<String> newCities) { this.cities.clear(); this.cities.addAll(newCities); notifyDataSetChanged(); } // 其他原有方法保持不变 }
- 修改ViewHolder,缓存CityRvAdapter:
public class ViewHolder extends RecyclerView.ViewHolder { private CountryBinding binding; private CityRvAdapter cityRvAdapter; public ViewHolder(CountryBinding binding) { super(binding.getRoot()); this.binding = binding; // 初始化一次Adapter,后续只更新数据 cityRvAdapter = new CityRvAdapter(new ArrayList<>()); binding.cityListRv.setAdapter(cityRvAdapter); } // 提供更新城市数据的方法 public void setCities(List<String> cities) { cityRvAdapter.updateCities(cities); } }
- 最后修改
onBindViewHolder:
@Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { CountryList countryList = countryArrayList.get(position); holder.binding.countryName.setText(countryList.getCountry()); // 只更新城市数据,不新建Adapter holder.setCities(countryList.getCitiesList()); holder.binding.cityListRv.setVisibility(countryList.isExpanded() ? View.VISIBLE : View.GONE); holder.binding.expandCountryButton.setOnClickListener(view -> { boolean newState = !countryList.isExpanded(); countryList.setExpanded(newState); notifyItemChanged(position); }); }
为什么这样修复?
把展开状态和数据模型绑定后,每次ViewHolder被复用时,都会从对应的数据项中读取正确的状态,不会出现「未操作的item自动展开」的问题。点击事件更新数据后调用notifyItemChanged,能确保界面和数据状态完全同步。
内容的提问来源于stack exchange,提问作者eliftekin
相关产品推荐
相关产品推荐

