ViewPager滑动切换卡片时IndexOutOfBoundsException异常排查
问题现象
ViewPager滑动切换卡片时触发崩溃,捕获到如下异常:
java.lang.IndexOutOfBoundsException: index=5 count=4
Logcat定位异常关联点为自定义PagerAdapter的instantiateItem方法中container.addView(view, position)代码行,初步怀疑数据源ArrayList存在问题。
根因定位
核心崩溃原因是错误将数据源的position参数作为ViewGroup的子View插入索引传入addView方法:
container.addView(view, index)方法要求传入的index必须在0 ~ container.getChildCount()范围内,这个index是View在容器内部子View列表的位置,和数据源的总长度、数据源位置没有直接关系。- ViewPager默认只会缓存当前页+左右相邻页共3个左右的子View,滑动过程中会动态回收、创建View,容器内实际存在的子View数量远小于数据源总长度。当滑动到position=5的卡片时,容器内仅存在4个子View(对应日志里的count=4),此时要求把新View插入到index=5的位置,直接触发索引越界。
除此之外代码里还有两个隐藏问题:
- 贴出的
DashboardFlavorModel类缺失全参构造方法、count字段的getter/setter,和初始化时传3个参数实例化Model的逻辑不匹配 - 加减按钮的点击事件捕获了instantiateItem时的初始count值,点击修改后不会同步刷新界面显示的数量,属于功能逻辑bug
修复方案
- 修正addView调用:删除传入的position参数,直接调用
container.addView(view)即可,ViewPager内部会自行管理子View的排列顺序,不需要手动指定插入位置 - 补全Model类缺失的方法
- 修复加减按钮的计数逻辑,点击时实时读取Model的最新count值,修改后同步刷新UI
核心修改代码
- 修正instantiateItem方法中的addView逻辑与按钮点击逻辑
@NonNull @Override public Object instantiateItem(@NonNull ViewGroup container, int position) { View view = LayoutInflater.from(context).inflate(R.layout.flavor_item, container, false); ImageView imageIv = view.findViewById(R.id.imageIv); TextView flavorTv = view.findViewById(R.id.flavorTv); TextView quantityTv = view.findViewById(R.id.quantityTv); ImageButton minusbutton = view.findViewById(R.id.minusbutton); ImageButton plusbutton = view.findViewById(R.id.plusbutton); DashboardFlavorModel model = modelArrayList.get(position); imageIv.setImageResource(model.getImage()); flavorTv.setText(model.getTitle()); quantityTv.setText(String.valueOf(model.getCount())); minusbutton.setOnClickListener(v -> { int currentCount = model.getCount(); if (currentCount > 0) { model.setCount(currentCount - 1); quantityTv.setText(String.valueOf(model.getCount())); } else { Snackbar.make(v, "You cannot have less than 0 QTY", Snackbar.LENGTH_LONG).show(); } }); plusbutton.setOnClickListener(v -> { int currentCount = model.getCount(); model.setCount(currentCount + 1); quantityTv.setText(String.valueOf(model.getCount())); }); // 修复:删除position参数,不手动指定插入位置 container.addView(view); return view; }
- 补全DashboardFlavorModel类
public class DashboardFlavorModel { String title; int image,count; // 补全全参构造 public DashboardFlavorModel(String title, int image, int count) { this.title = title; this.image = image; this.count = count; } // 补全count字段的getter/setter public int getCount() { return count; } public void setCount(int count) { this.count = count; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getImage() { return image; } public void setImage(int image) { this.image = image; } }
验证说明
修改后ViewPager滑动过程中创建子View时,会默认将新View添加到容器子列表末尾,由ViewPager内部自行处理布局位置,不会再出现插入索引超出容器子View数量的越界问题;加减按钮点击后也会实时刷新显示的数量值,功能正常。
内容的提问来源于stack exchange,提问作者Zhe
相关产品推荐
相关产品推荐

