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

RecyclerView嵌入广告后显示异常及崩溃问题求助

问题排查与修复方案

我来帮你分析这两个问题的根源,并给出具体的修复步骤:


问题1:首位置显示广告、第一条课程完全消失

根源分析

你在getItemViewType中设置position % ITEMS_PER_AD == 0时显示广告,这会让position=0(首位置)直接显示广告。更关键的是,在绑定课程数据时,你直接用data.get(position)获取课程——但position是包含广告的全局列表位置,比如position=1对应的是data.get(1)(第二个课程),而data.get(0)(第一个课程)没有任何position对应,导致它完全不显示。

修复方案

  1. 调整课程索引计算逻辑:在绑定课程数据时,需要减去前面已经出现的广告数量,得到课程在data列表中的真实索引:
// 在COURSE_VIEW_TYPE分支中替换原有的Course获取逻辑
int adCountBefore = position / ViewCoursesActivity.ITEMS_PER_AD;
int courseIndex = position - adCountBefore;
Course currentCourse = data.get(courseIndex);
  1. 可选:移除首位置广告:如果你希望首位置显示课程,可以修改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)

根源分析

这个问题有两个核心原因:

  1. getItemCount返回值错误:你只返回了课程数量,但实际列表应该包含课程+广告的总数量,导致RecyclerView滚动时请求超出课程数量的position,触发越界。
  2. 广告索引获取错误:你用ad.get(position)获取广告,但position是全局位置,而ad列表的长度远小于全局位置数,比如position=8时,ad列表可能只有1个元素,直接触发索引越界。

修复方案

  1. 修正getItemCount返回值:计算课程+广告的总数量,广告数按每8个课程插入1个计算:
@Override
public int getItemCount() {
    if (data.isEmpty()) return 0;
    // 总条目数 = 课程数 + 广告数(每8个课程插1个)
    return data.size() + (data.size() / ViewCoursesActivity.ITEMS_PER_AD);
}
  1. 修正广告索引计算逻辑:根据全局位置计算广告在ad列表中的真实索引:
// 在AD_VIEW_TYPE分支中替换原有的AdView获取逻辑
int adIndex = position / (ViewCoursesActivity.ITEMS_PER_AD + 1);
// 增加越界判断,避免崩溃
if (adIndex >= ad.size()) return;
AdView adView = (AdView) ad.get(adIndex);
  1. 调整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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:44:34