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

RecyclerView适配器报错:两个ViewHolder稳定ID重复,求解决方案

解决方案

核心问题在于:队列中重复的歌曲共享同一个songId,导致getItemId返回的ID不唯一,RecyclerView无法区分不同的列表项,进而引发状态更新异常。下面给出两种可行方案:

方案一:用组合模式创建独立队列条目(推荐)

放弃继承Song,转而创建一个专门的QueueItem类,包装歌曲信息、唯一标识和播放状态,彻底区分队列中的每个独立条目:

// 定义队列条目类,包含唯一ID、歌曲本体和播放状态
data class QueueItem(
    val uniqueId: Long, // 每个队列条目的全局唯一ID
    val song: Song,
    val isPlaying: Boolean
)

实现细节:

  1. 生成唯一ID:
    • 本地队列可维护一个自增计数器,每次添加歌曲时递增赋值(比如var idCounter = 0L; val newId = idCounter++)
    • 也可用UUID生成:UUID.randomUUID().mostSignificantBits(取Long部分,冲突概率极低)
  2. 适配器修改:
    数据集改为List<QueueItem>,并在getItemId中返回唯一ID:
    override fun getItemId(position: Int): Long {
        return dataset[position].uniqueId
    }
    

这种方式用组合替代继承,灵活性更高,避免了父类结构变化带来的维护问题,同时保证每个列表项ID绝对唯一。

方案二:修正QueueSong的实现(若坚持继承)

如果必须继承Song,需确保queueId是真正唯一的标识,而非依赖hashCode(hashCode存在重复风险):

data class QueueSong(
    private val song: Song,
    // 初始化时生成唯一ID,避免hashCode重复问题
    val queueId: Long = UUID.randomUUID().mostSignificantBits
) : Song(song) {
    // 若Song是data class,建议重写equals和hashCode,仅以queueId作为判断依据
    override fun equals(other: Any?): Boolean {
        if (this === other) return true
        if (javaClass != other?.javaClass) return false
        other as QueueSong
        return queueId == other.queueId
    }

    override fun hashCode(): Int {
        return queueId.hashCode()
    }
}

然后适配器的getItemId返回queueId:

override fun getItemId(position: Int): Long {
    return dataset[position].queueId
}

额外注意事项

  • 确保setHasStableIds(true)在适配器初始化时仅调用一次
  • 更新播放状态时,修改对应队列条目的isPlaying属性后,调用notifyItemChanged(position)而非notifyDataSetChanged,提升性能并避免列表闪烁

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 12:57:16