Android中RecyclerView滚动时SeekBar进度异常问题求助
RecyclerView音频SeekBar滚动异常问题解决方案
核心原因
RecyclerView的ViewHolder复用机制导致:滚动时被回收的ViewHolder重新绑定数据,若未正确同步当前播放的音频进度,会默认显示SeekBar的最大值(即末尾);再次滚动回来时,ViewHolder重新绑定到正确的播放状态,进度恢复正常。
具体解决方案
1. 维护全局播放状态记录
创建单例类统一管理当前播放的音频信息,避免ViewHolder复用后状态丢失:
public class AudioPlayManager { private static AudioPlayManager instance; private String currentAudioId; // 当前播放的音频唯一标识 private int currentProgress; // 当前播放进度 private int totalDuration; // 音频总时长 private boolean isPlaying; // 播放状态 private AudioPlayManager() {} public static AudioPlayManager getInstance() { if (instance == null) { instance = new AudioPlayManager(); } return instance; } // 更新播放状态 public void updatePlayState(String audioId, int progress, int duration, boolean playing) { currentAudioId = audioId; currentProgress = progress; totalDuration = duration; isPlaying = playing; } // 提供getter方法获取状态 public String getCurrentAudioId() { return currentAudioId; } public int getCurrentProgress() { return currentProgress; } public int getTotalDuration() { return totalDuration; } public boolean isPlaying() { return isPlaying; } }
2. 绑定ViewHolder时同步播放状态
在onBindViewHolder方法中,根据全局状态判断当前列表项是否为正在播放的音频,同步SeekBar和图标状态:
@Override public void onBindViewHolder(@NonNull AudioViewHolder holder, int position) { AudioMessage message = messageList.get(position); AudioPlayManager playManager = AudioPlayManager.getInstance(); // 匹配当前播放音频,同步进度和图标 if (message.getId().equals(playManager.getCurrentAudioId())) { holder.seekBar.setMax(playManager.getTotalDuration()); holder.seekBar.setProgress(playManager.getCurrentProgress()); holder.playBtn.setImageResource(playManager.isPlaying() ? R.drawable.ic_pause : R.drawable.ic_play); } else { // 非播放状态,重置SeekBar和图标 holder.seekBar.setProgress(0); holder.playBtn.setImageResource(R.drawable.ic_play); } // 播放按钮点击逻辑 holder.playBtn.setOnClickListener(v -> { if (message.getId().equals(playManager.getCurrentAudioId()) && playManager.isPlaying()) { // 暂停当前音频 pauseCurrentAudio(); playManager.updatePlayState(message.getId(), playManager.getCurrentProgress(), playManager.getTotalDuration(), false); holder.playBtn.setImageResource(R.drawable.ic_play); } else { // 切换播放新音频 stopCurrentAudio(); startAudio(message.getAudioPath(), message.getId()); int duration = getAudioDuration(message.getAudioPath()); playManager.updatePlayState(message.getId(), 0, duration, true); holder.playBtn.setImageResource(R.drawable.ic_pause); } }); }
3. 实时同步播放进度到全局状态
在音频播放的进度回调中,同时更新全局状态,确保ViewHolder复用后能获取到最新进度:
private Handler progressHandler = new Handler(); private Runnable progressRunnable = new Runnable() { @Override public void run() { if (mediaPlayer != null && mediaPlayer.isPlaying()) { int currentPos = mediaPlayer.getCurrentPosition(); int totalDur = mediaPlayer.getDuration(); // 更新全局状态 AudioPlayManager.getInstance().updatePlayState(currentAudioId, currentPos, totalDur, true); // 更新当前显示的ViewHolder进度(可选,若需要实时刷新) if (currentPlayingViewHolder != null) { currentPlayingViewHolder.seekBar.setProgress(currentPos); } progressHandler.postDelayed(this, 100); } } };
4. 处理ViewHolder回收时的资源清理
在onViewRecycled方法中,清理当前播放ViewHolder的引用和进度更新任务,避免内存泄漏:
@Override public void onViewRecycled(@NonNull AudioViewHolder holder) { super.onViewRecycled(holder); AudioPlayManager playManager = AudioPlayManager.getInstance(); if (messageList.get(holder.getAdapterPosition()).getId().equals(playManager.getCurrentAudioId())) { progressHandler.removeCallbacks(progressRunnable); currentPlayingViewHolder = null; } }
内容的提问来源于stack exchange,提问作者kirubakaran
相关产品推荐
相关产品推荐

