简体   繁体   中英

Only the SeekBar in last item of RecyclerView is working

I am trying to create an app where I am using RecyclerView to show/play list of audio which is to be streamed. Each item in the RecyclerView has a SeekBar , a button, and TextView for audio timer.

The problem I am facing is that when I play the audio, the seekbar is running only for the last item of the RecyclerView . I have seen similar other problems but have not been able to solve mine. Here is the code I am using for the Adapter:

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;
}

}

Image of the Layout

图片

You have created a runnable. So a new thread is created to update your seekbar. In that thread you have use mSeekBar.setProgress(mMediaPlayer.getCurrentPosition()); to update progress which is not synchronized with mail thread. While executing each item view a separate thread is created and mSeekbar instance does not retain the proper instance(ie) when a new view is created a new thread created and mSeekbar get new instance. Finally, the last instance of seekbar assigned to mSeekbar. So updation takes place only in last seek bar. Why did you create another runnable for progress bar update?

I copied the Runnable portion into the OnClickListener and that solve the problem. Updated Code:

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;
}

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM