RecyclerView嵌入广告后显示异常及崩溃问题求助
问题排查与修复方案
我来帮你分析这两个问题的根源,并给出具体的修复步骤:
问题1:首位置显示广告、第一条课程完全消失
根源分析
你在getItemViewType中设置position % ITEMS_PER_AD == 0时显示广告,这会让position=0(首位置)直接显示广告。更关键的是,在绑定课程数据时,你直接用data.get(position)获取课程——但position是包含广告的全局列表位置,比如position=1对应的是data.get(1)(第二个课程),而data.get(0)(第一个课程)没有任何position对应,导致它完全不显示。
修复方案
- 调整课程索引计算逻辑:在绑定课程数据时,需要减去前面已经出现的广告数量,得到课程在
data列表中的真实索引:
// 在COURSE_VIEW_TYPE分支中替换原有的Course获取逻辑 int adCountBefore = position / ViewCoursesActivity.ITEMS_PER_AD; int courseIndex = position - adCountBefore; Course currentCourse = data.get(courseIndex);
- 可选:移除首位置广告:如果你希望首位置显示课程,可以修改
getItemViewType的判断逻辑:
@Override public int getItemViewType(int position) { // 跳过首位置,从第8个位置开始每8个显示广告 return (position != 0 && position % ViewCoursesActivity.ITEMS_PER_AD == 0) ? AD_VIEW_TYPE : COURSE_VIEW_TYPE; }
问题2:滚动时崩溃(IndexOutOfBoundsException)
根源分析
这个问题有两个核心原因:
getItemCount返回值错误:你只返回了课程数量,但实际列表应该包含课程+广告的总数量,导致RecyclerView滚动时请求超出课程数量的position,触发越界。- 广告索引获取错误:你用
ad.get(position)获取广告,但position是全局位置,而ad列表的长度远小于全局位置数,比如position=8时,ad列表可能只有1个元素,直接触发索引越界。
修复方案
- 修正
getItemCount返回值:计算课程+广告的总数量,广告数按每8个课程插入1个计算:
@Override public int getItemCount() { if (data.isEmpty()) return 0; // 总条目数 = 课程数 + 广告数(每8个课程插1个) return data.size() + (data.size() / ViewCoursesActivity.ITEMS_PER_AD); }
- 修正广告索引计算逻辑:根据全局位置计算广告在
ad列表中的真实索引:
// 在AD_VIEW_TYPE分支中替换原有的AdView获取逻辑 int adIndex = position / (ViewCoursesActivity.ITEMS_PER_AD + 1); // 增加越界判断,避免崩溃 if (adIndex >= ad.size()) return; AdView adView = (AdView) ad.get(adIndex);
- 调整Activity中的广告添加逻辑:根据课程数量动态添加对应数量的广告,而不是初始时只加1个:
// 修改Activity中的addBannerAds方法 private void addBannerAds(int courseCount) { data.clear(); int adCount = courseCount / ViewCoursesActivity.ITEMS_PER_AD; for (int i = 0; i < adCount; i++) { final AdView adView = new AdView(ViewCoursesActivity.this); adView.setAdSize(AdSize.SMART_BANNER); adView.setAdUnitId(AD_UNIT_ID); data.add(adView); } } // 在观察课程数据时调用 courseViewModel.getCourseByStudentId().observe(this, newData -> { adapter.setData(newData); addBannerAds(newData.size()); adapter.notifyDataSetChanged(); });
额外优化建议
- 动画逻辑优化:原来的动画逻辑会对广告项也应用动画,建议只在课程项上执行动画:
// 把动画逻辑移到COURSE_VIEW_TYPE分支内部 case COURSE_VIEW_TYPE: // ... 课程绑定逻辑 ... if (position > previousPosition) { AnimationUtil.animate(holder, true); } else { AnimationUtil.animate(holder, false); } previousPosition = position; break;
- 空指针防护:在适配器构造函数中对
ad列表做非空初始化:
public ViewCourseAdapter(Context context, List<Object> ad) { this.data = new ArrayList<>(); this.context = context; this.layoutInflater = LayoutInflater.from(context); this.ad = ad != null ? ad : new ArrayList<>(); }
内容的提问来源于stack exchange,提问作者Mugur
相关产品推荐
相关产品推荐

