只有 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;
}
}
我正在尝试创建一个应用程序,我正在使用 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;
}
}