I'm trying to use a SeekBar to display both the length of a track played by a MediaPlayer class and to enable seeking within the track.
Seeking within the track works well. However, updating the progress value using setProgress while the track is playing seems to cause a slight skip.
In the onCreate method I create a Thread with a loop which updates the SeekBar's progress value for the current track. This loop resets when the track is changed.
private void createProgressThread() {
_progressUpdater = new Runnable() {
@Override
public void run() {
//Exitting is set on destroy
while(!_exitting) {
_resetProgress = false;
if(_player.isPlaying()) {
try
{
int current = 0;
int total = _player.getDuration();
progressBar.setMax(total);
progressBar.setIndeterminate(false);
while(_player!=null && current<total && !_resetProgress){
try {
Thread.sleep(1000); //Update once per second
current = _player.getCurrentPosition();
//Removing this line, the track plays normally.
progressBar.setProgress(current);
} catch (InterruptedException e) {
} catch (Exception e){
}
}
}
catch(Exception e)
{
//Don't want this thread to intefere with the rest of the app.
}
}
}
}
};
Thread thread = new Thread(_progressUpdater);
thread.start();
}
Ideally I would rather not use a thread as I understand that this has disadvantages. Also please excuse the exception swallowing - it is difficult to keep checking for all MediaPlayer states in response to UI events. However, my real problem is that the music is skipping.
Could anyone suggest an alternative way to update the progress and explain why the call to setProgress is causing the track to skip even with the use of a seperate thread?
Thanks in advance.
I think the problem is that when you call the setProgress(), the onProgressChanged event is fired.
The listener (OnSeekBarChangeListener) have a method public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser). Here you should test if the listener was fired by a user action or from code. In your case, the fromUser variable should be false.
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(fromUser){
player.seekTo(x);
}
else{
// the event was fired from code and you shouldn't call player.seekTo()
}
}