0

I am actually creating an app with a button, a seekbar and an an image. The button is used to Play/Pause the music. the music played smooth before adding the seekbar. But, after writing the code for seekbar to progress with the position of music, the music seems to be a bit choppy. Also, i want to reset the position of seekbar to start and change the text on button to "Play" after the music is finished playing. Can any one tell me why the music is choppy after implementing seekbar? Also, suggest me how to deal after the music is finished playing. The coded i used is below:

public class MainActivity extends ActionBarActivity {

private MediaPlayer song;
private SeekBar seekbar;

private final Handler handler = new Handler();

private final Runnable updatePositionRunnable = new Runnable() {
        public void run() {
                updatePosition();
        }
};

//private boolean isPlaying = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    if (savedInstanceState == null) {
        getSupportFragmentManager().beginTransaction()
                .add(R.id.container, new PlaceholderFragment())
                .commit();
    }

    seekbar = (SeekBar)findViewById(R.id.musicSeekBar);
    song = MediaPlayer.create( MainActivity.this, R.raw.xyz);   
    seekbar.setMax(song.getDuration());

    final Button playButton = (Button)findViewById(R.id.playButton);


    playButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {


            if(song.isPlaying()){
                playButton.setText("Play");
                song.pause();
                //isPlaying = false;
                handler.removeCallbacks(updatePositionRunnable);
            }
            else{
                playButton.setText("Pause");
                song.start();
                //isPlaying = true;
                updatePosition();
            }
        }
    });

    song.setOnCompletionListener(new OnCompletionListener() {

        @Override
        public void onCompletion(MediaPlayer mp) {
            playButton.setText("Play");
            //seekbar.setProgress(0);
            //mp.stop();
        }
    });

    seekbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {


        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {


        }

        @Override
        public void onProgressChanged(SeekBar seekBar, int progress,
                boolean fromUser) {
            song.seekTo(progress);
        }
    });
private void updatePosition(){
    handler.removeCallbacks(updatePositionRunnable);

    seekbar.setProgress(song.getCurrentPosition());

    handler.postDelayed(updatePositionRunnable, 2000);
}


@Override
public void onBackPressed() {

    super.onBackPressed();
    song.stop();
    song.release();
}

2 Answers2

0

When you update the progress on the seekbar from your updatePosition method every 2 seconds, the onProgressChanged method in your listener will be called, which will set the position of the playback and cause a slight blip. You might expect onProgressChanged to be called only when the user interacts with the SeekBar but unfortunately that isn't the case.

I'm not aware of a clean solution to this. What you can do is set a boolean flag in your code immediately before calling seekbar.setProgress that indicates the next onProgressChanged callback was not caused by the user, so you can ignore it. You should use an AtomicBoolean for this purpose because the events may come from different threads.

Dave Morrissey
  • 4,371
  • 1
  • 23
  • 31
0

this worked for me:

sBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {

        boolean userTouch;
        @Override
        public void onStopTrackingTouch(SeekBar arg0) {
            userTouch = false;
        }
        @Override
        public void onStartTrackingTouch(SeekBar arg0) {
            userTouch = true;
        }
        @Override
        public void onProgressChanged(SeekBar arg0, int arg1, boolean arg2) {
            if(mPlayer.isPlaying() && arg2)
                mPlayer.seekTo(arg1);
            }
    });
GabrieleG
  • 107
  • 1
  • 7
  • There's no need to have the boolean `userTouch` since the third argument in `onProgressChanged` is a boolean that's "True if the progress change was initiated by the user." [Documentation](http://developer.android.com/reference/android/widget/SeekBar.OnSeekBarChangeListener.html)That makes your overriding of `onStart...` and `onStop...` useless. Just trying to save you some code. =) – Charles Caldwell Dec 04 '15 at 22:19