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

Android RecyclerView启用SLIDER_VIEW时ITEM_VIEW项丢失冲突问题

问题现象
  • 开启轮播滑块开关(Config.ENABLE_RECENT_SLIDER=true),将SLIDER_VIEW放置在列表0号位置时,SLIDER_VIEW与ITEM_VIEW出现位置合并问题:ITEM_VIEW第一项无法正常展示,列表最后一项丢失。
    轮播开启时异常效果
  • 关闭轮播滑块开关时,ITEM_VIEW第一项可正常展示。
    轮播关闭时正常效果
实现目标

列表顶部正常展示SLIDER_VIEW轮播组件,同时缺失的ITEM_VIEW首项正常渲染,所有列表项(广告项、轮播项、壁纸项)无丢失。

故障原因

核心错误集中在位置计算逻辑,共3处:

  1. getItemCount()未将开启轮播时新增的SLIDER_VIEW计入总项数,总长度少1,直接导致列表最后一项被截断。
  2. getItemViewType()判断广告位、普通项位置时,未将轮播项占用的位置纳入偏移计算,位置0被轮播占用后,后续广告位判断、普通项索引全部错位,导致第一项壁纸项被覆盖。
  3. onBindViewHolder()中计算普通壁纸项对应mData索引时,未扣除轮播占用的位置,且使用Math.round(position / Config.NATIVE_ADS_PER_ITEM)计算广告偏移量逻辑错误,整数除法直接取整即可,四舍五入会导致广告位附近索引计算偏差。
修复代码

仅需修改3个核心方法,其余业务逻辑无需调整:

1. 修正总项数计算逻辑

@Override
public int getItemCount() {
    if (mData == null) return 0;
    // 整数除法直接计算广告数量,无需四舍五入
    int adCount = mData.size() / Config.NATIVE_ADS_PER_ITEM;
    int total = mData.size() + adCount;
    // 开启轮播时总长度+1,计入顶部轮播项
    if (Config.ENABLE_RECENT_SLIDER) {
        total += 1;
    }
    return total;
}

2. 修正项类型判断逻辑

@Override
public int getItemViewType(int position) {
    // 开启轮播时0号位置固定为轮播项
    if (position == 0 && Config.ENABLE_RECENT_SLIDER) {
        return SLIDER_VIEW;
    }
    // 扣除轮播占用的位置偏移后,再判断广告位
    int adjustPos = Config.ENABLE_RECENT_SLIDER ? position - 1 : position;
    if ((adjustPos + 1) % Config.NATIVE_ADS_PER_ITEM == 0) {
        return AD_VIEW;
    }
    return ITEM_VIEW;
}

3. 修正绑定阶段的数据源索引计算

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
    status = sharedPreferences.getString("status", "free");
    StaggeredGridLayoutManager.LayoutParams layoutParams = (StaggeredGridLayoutManager.LayoutParams) holder.itemView.getLayoutParams();
    
    if (holder.getItemViewType() == ITEM_VIEW) {
        // 第一步:扣除轮播项的位置偏移
        int adjustPos = Config.ENABLE_RECENT_SLIDER ? position - 1 : position;
        // 第二步:扣除前面已加载的广告项数量,得到壁纸数据在mData中的真实索引
        int dataPos = adjustPos - (adjustPos / Config.NATIVE_ADS_PER_ITEM);
        ((MainViewHolder) holder).bindData(mData.get(dataPos), listener, position);

    } else if (holder.getItemViewType() == AD_VIEW) {
        // 原代码用&是按位与,这里改为逻辑与&&
        if (Config.ENABLE_ADS && status.equals("free")) {
            ((AdViewHolder) holder).bindAdData();
            layoutParams.setFullSpan(true);
        }

    } else if (holder.getItemViewType() == SLIDER_VIEW) {
        layoutParams.setFullSpan(true);
        ((SliderViewHolder) holder).bindSliderData();
    }
}
可选优化
  • 当前SliderViewHolder每次绑定都会新建图片列表、重复添加页面监听、重复发起网络请求,上下滑动轮播项会重复加载,建议将轮播数据初始化、网络请求逻辑移至Adapter构造函数执行,bindSliderData()仅做视图绑定,避免重复请求和内存泄漏。
  • 轮播使用的Timer需要在RecyclerView回收、关联Activity/Fragment销毁时调用cancel()方法释放,避免内存泄漏。

内容的提问来源于stack exchange,提问作者Taiyab

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:42:15