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

RecyclerView ViewHolder滚动后状态错乱问题求助

Hey, I've run into this exact headache with RecyclerViews before—total classic issue tied to how ViewHolder reuse works. Let's break down why this is happening and how to fix it for good.

Why This Happens

RecyclerView reuses ViewHolders to save memory instead of creating a new one for every list item. When you scroll, off-screen ViewHolders get pulled back into view and rebound to new data. If you're storing playback state (like play/pause visibility, seekbar status) only in the ViewHolder itself, that old state gets carried over to whatever new list item the ViewHolder is now displaying. The "regular interval" you're seeing is exactly the size of RecyclerView's ViewHolder pool—once it cycles through those, the same reused states pop up again.

The Fix: Bind State to Your Data Source, Not the ViewHolder

The key rule here is: all UI state for a list item should live in your data model, not the ViewHolder. Here's how to implement this step by step:

  1. Add State Fields to Your Data Model
    Update your song/track data class to include fields that track playback state. For example:

    data class Track(
        val id: String,
        val title: String,
        val artist: String,
        var isPlaying: Boolean = false,
        var currentSeekProgress: Int = 0
    )
    

    This way, every track's playback state is tied directly to its data, not the temporary ViewHolder that displays it.

  2. Refresh UI from the Data Source in onBindViewHolder
    Every time a ViewHolder is bound to a new item, you pull the state from the data model and update the UI accordingly—never rely on the ViewHolder's existing state. Here's what that looks like:

    override fun onBindViewHolder(holder: TrackViewHolder, position: Int) {
        val currentTrack = trackList[position]
    
        // Set basic content first
        holder.trackTitle.text = currentTrack.title
        holder.trackArtist.text = currentTrack.artist
    
        // Update playback-related UI based on data model state
        if (currentTrack.isPlaying) {
            holder.playBtn.visibility = View.GONE
            holder.pauseBtn.visibility = View.VISIBLE
            holder.seekBar.visibility = View.VISIBLE
            holder.seekBar.progress = currentTrack.currentSeekProgress
        } else {
            holder.playBtn.visibility = View.VISIBLE
            holder.pauseBtn.visibility = View.GONE
            holder.seekBar.visibility = View.GONE
        }
    
        // Handle play/pause clicks
        holder.playBtn.setOnClickListener {
            // Update the data model first
            currentTrack.isPlaying = true
            // Notify RecyclerView to refresh this specific item
            notifyItemChanged(position)
            // Trigger your actual playback logic here
        }
    
        holder.pauseBtn.setOnClickListener {
            currentTrack.isPlaying = false
            notifyItemChanged(position)
            // Trigger pause logic here
        }
    }
    
  3. Handle Global Playback State (If Only One Track Plays At a Time)
    If your app only allows one track to play at once, you need to reset the previous playing track's state when a new one starts. Add a variable to track the current playing position, then update both items when switching:

    private var currentPlayingPosition: Int = -1
    
    // Inside your play button click listener:
    if (currentPlayingPosition != -1) {
        // Reset the old playing track's state
        trackList[currentPlayingPosition].isPlaying = false
        notifyItemChanged(currentPlayingPosition)
    }
    // Set the new track as playing
    currentPlayingPosition = position
    trackList[position].isPlaying = true
    notifyItemChanged(position)
    
  4. Update Seekbar Progress Correctly
    For real-time seekbar updates during playback, don't modify the ViewHolder directly. Instead, update the currentSeekProgress field in the data model for the playing track, then call notifyItemChanged(currentPlayingPosition) to refresh the UI.

Quick Recap

The root issue is that ViewHolders are temporary and reused—so never store item-specific state in them. Always tie state to your data model, and refresh the UI from that model every time the ViewHolder is bound. This will eliminate those weird state swaps when scrolling.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 03:41:47