只有 RecyclerView 的最后一项中的 SeekBar 有效

Only the SeekBar in last item of RecyclerView is working

我正在尝试创建一个应用程序,我正在使用 RecyclerView 到 show/play 要流式传输的音频列表。 RecyclerView 中的每个项目都有一个 SeekBar、一个按钮和用于音频计时器的 TextView

我面临的问题是,当我播放音频时,seekbar 是 运行 只有 RecyclerView 的最后一项。我见过类似的其他问题,但无法解决我的问题。这是我用于适配器的代码:

public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.ViewHolder> {
Context context;
LayoutInflater inflator;
ArrayList<AudioModel> list = new ArrayList();
SeekBar mSeekBar;
TextView mTvAudioLength;
MediaPlayer mMediaPlayer;

public AudioAdapter(Context context, ArrayList<AudioModel> list) {
    this.context = context;
    this.list = list;
    inflator = LayoutInflater.from(context);
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = inflator.inflate(R.layout.audio_recyclerview_layout, parent, false);
    AudioAdapter.ViewHolder viewHolder = new AudioAdapter.ViewHolder(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {

    final AudioModel modelList = list.get(position);
    //holder.tvAudioLength.setText(modelList.duration);
    holder.tvAudioName.setText(modelList.name);

    // Initializing MediaPlayer
    final MediaPlayer mediaPlayer = new MediaPlayer();

    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mediaPlayer.setDataSource(modelList.url);
        mediaPlayer.prepare();// might take long for buffering.
    } catch (IOException e) {
        e.printStackTrace();
    }
    mMediaPlayer = mediaPlayer;
    mTvAudioLength = holder.tvAudioLength;
    mSeekBar = holder.seekBar;
    holder.seekBar.setMax(mediaPlayer.getDuration());
    run.run();
    holder.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (mediaPlayer != null && fromUser) {
                mediaPlayer.seekTo(progress);
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });
    holder.tvAudioLength.setText(calculateDuration(mediaPlayer.getDuration()));
    holder.btn_play.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (!mediaPlayer.isPlaying()) {
                mediaPlayer.start();
                holder.btn_play.setText("Pause");
            } else {
                mediaPlayer.pause();
                holder.btn_play.setText("Play");
            }
        }
    });
}
Runnable run = new Runnable() {
    @Override
    public void run() {
        // Updateing SeekBar every 100 miliseconds
        Handler seekHandler = new Handler();
        mSeekBar.setProgress(mMediaPlayer.getCurrentPosition());
        seekHandler.postDelayed(run, 100);
        //For Showing time of audio(inside runnable)
        int miliSeconds = mMediaPlayer.getCurrentPosition();
        if(miliSeconds!=0) {
            //if audio is playing, showing current time;
            long minutes = TimeUnit.MILLISECONDS.toMinutes(miliSeconds);
            long seconds = TimeUnit.MILLISECONDS.toSeconds(miliSeconds);
            if (minutes == 0) {
                mTvAudioLength.setText("0:" + seconds);
            } else {
                if (seconds >= 60) {
                    long sec = seconds - (minutes * 60);
                    mTvAudioLength.setText(minutes + ":" + sec);
                }
            }
        }else{
            //Displaying total time if audio not playing
            int totalTime=mMediaPlayer.getDuration();
            long minutes = TimeUnit.MILLISECONDS.toMinutes(totalTime);
            long seconds = TimeUnit.MILLISECONDS.toSeconds(totalTime);
            if (minutes == 0) {
                mTvAudioLength.setText("0:" + seconds);
            } else {
                if (seconds >= 60) {
                    long sec = seconds - (minutes * 60);
                    mTvAudioLength.setText(minutes + ":" + sec);
                }
            }
        }
    }

};

@Override
public int getItemCount() {
    return list.size();
}

class ViewHolder extends RecyclerView.ViewHolder {
    Button btn_play;
    TextView tvAudioLength;
    TextView tvAudioName;
    SeekBar seekBar;

    public ViewHolder(View itemView) {
        super(itemView);
       // mTvAudioLength =(TextView) itemView.findViewById(R.id.tv_audio_lenght);
       // mSeekBar = (SeekBar) itemView.findViewById(R.id.seekBar);
        btn_play = (Button) itemView.findViewById(R.id.btn_play);
        tvAudioLength = (TextView) itemView.findViewById(R.id.tv_audio_lenght);
        tvAudioName = (TextView) itemView.findViewById(R.id.tv_audio_name);
        seekBar = (SeekBar) itemView.findViewById(R.id.seekBar);
        //seekBar.setTag(itemView.findViewById(R.id.seekBar));
    }
}

private String calculateDuration(int duration) {
    String finalDuration = "";
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
    if (minutes == 0) {
        finalDuration = "0:" + seconds;
    } else {
        if (seconds >= 60) {
            long sec = seconds - (minutes * 60);
            finalDuration = minutes + ":" + sec;
        }
    }
    return finalDuration;
}

}

布局图片

您已经创建了一个可运行的。因此,创建了一个新线程来更新您的搜索栏。在该线程中,您使用 mSeekBar.setProgress(mMediaPlayer.getCurrentPosition()); 来更新与邮件线程不同步的进度。在执行每个项目视图时,会创建一个单独的线程,并且 mSeekbar 实例不会保留正确的实例(即)当创建新视图时,会创建一个新线程,并且 mSeekbar 会获取新实例。最后,seekbar 的最后一个实例分配给mSeekbar。所以更新只发生在最后一个搜索栏中。为什么要为进度条更新创建另一个 runnable?

我将 Runnable 部分复制到 OnClickListener 中并解决了问题。 更新代码:

public class AudioAdapter extends RecyclerView.Adapter<AudioAdapter.ViewHolder> {
Context context;
LayoutInflater inflator;
ArrayList<AudioModel> list = new ArrayList();
Handler seekHandler = new Handler();
Runnable run;

public AudioAdapter(Context context, ArrayList<AudioModel> list) {
    this.context = context;
    this.list = list;
    inflator = LayoutInflater.from(context);
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View view = inflator.inflate(R.layout.audio_recyclerview_layout, parent, false);
    AudioAdapter.ViewHolder viewHolder = new AudioAdapter.ViewHolder(view);
    return viewHolder;
}

@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {

    final AudioModel modelList = list.get(position);
    holder.tvAudioName.setText(modelList.name);

    // Initializing MediaPlayer
    final MediaPlayer mediaPlayer = new MediaPlayer();

    mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
    try {
        mediaPlayer.setDataSource(modelList.url);
        mediaPlayer.prepare();// might take long for buffering.
    } catch (IOException e) {
        e.printStackTrace();
    }

    holder.seekBar.setMax(mediaPlayer.getDuration());
    holder.seekBar.setTag(position);
    //run.run();
    holder.seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            if (mediaPlayer != null && fromUser) {
                mediaPlayer.seekTo(progress);
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {

        }
    });
    holder.tvAudioLength.setText("0:00/"+calculateDuration(mediaPlayer.getDuration()));
    holder.btn_play.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (!mediaPlayer.isPlaying()) {
                mediaPlayer.start();
                holder.btn_play.setText("Pause");
                 run = new Runnable() {
                    @Override
                    public void run() {
                        // Updateing SeekBar every 100 miliseconds
                        holder.seekBar.setProgress(mediaPlayer.getCurrentPosition());
                        seekHandler.postDelayed(run, 100);
                        //For Showing time of audio(inside runnable)
                        int miliSeconds = mediaPlayer.getCurrentPosition();
                        if(miliSeconds!=0) {
                            //if audio is playing, showing current time;
                            long minutes = TimeUnit.MILLISECONDS.toMinutes(miliSeconds);
                            long seconds = TimeUnit.MILLISECONDS.toSeconds(miliSeconds);
                            if (minutes == 0) {
                               holder.tvAudioLength.setText("0:" + seconds + "/" +calculateDuration(mediaPlayer.getDuration()));
                            } else {
                                if (seconds >= 60) {
                                    long sec = seconds - (minutes * 60);
                                    holder.tvAudioLength.setText(minutes + ":" + sec+ "/" +calculateDuration(mediaPlayer.getDuration()));
                                }
                            }
                        }else{
                            //Displaying total time if audio not playing
                            int totalTime=mediaPlayer.getDuration();
                            long minutes = TimeUnit.MILLISECONDS.toMinutes(totalTime);
                            long seconds = TimeUnit.MILLISECONDS.toSeconds(totalTime);
                            if (minutes == 0) {
                                holder.tvAudioLength.setText("0:" + seconds);
                            } else {
                                if (seconds >= 60) {
                                    long sec = seconds - (minutes * 60);
                                    holder.tvAudioLength.setText(minutes + ":" + sec);
                                }
                            }
                        }
                    }

                };
                run.run();
            } else {
                mediaPlayer.pause();
                holder.btn_play.setText("Play");
            }
        }
    });
}

@Override
public int getItemCount() {
    return list.size();
}

class ViewHolder extends RecyclerView.ViewHolder {
    Button btn_play;
    TextView tvAudioLength;
    TextView tvAudioName;
    SeekBar seekBar;

    public ViewHolder(View itemView) {
        super(itemView);
       // mTvAudioLength =(TextView) itemView.findViewById(R.id.tv_audio_lenght);
       // mSeekBar = (SeekBar) itemView.findViewById(R.id.seekBar);
        btn_play = (Button) itemView.findViewById(R.id.btn_play);
        tvAudioLength = (TextView) itemView.findViewById(R.id.tv_audio_lenght);
        tvAudioName = (TextView) itemView.findViewById(R.id.tv_audio_name);
        seekBar = (SeekBar) itemView.findViewById(R.id.seekBar);

    }
}

private String calculateDuration(int duration) {
    String finalDuration = "";
    long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
    long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
    if (minutes == 0) {
        finalDuration = "0:" + seconds;
    } else {
        if (seconds >= 60) {
            long sec = seconds - (minutes * 60);
            finalDuration = minutes + ":" + sec;
        }
    }
    return finalDuration;
}

}