pouzzler
pouzzler

Reputation: 1834

MediaPlayer, ProgressBar

Is this the correct way to update a ProgressBar when playing Media? I figured there would be a callback in MediaPlayer, but I couldn't find it.

mediaPlayer.start();
final SeekBar progress = (SeekBar) dialog.findViewById(R.id.seekBar1);
progress.setMax(mediaPlayer.getDuration());
new CountDownTimer(mediaPlayer.getDuration(), 250) {
  public void onTick(long millisUntilFinished) {
    progress.setProgress(progress.getProgress() + 250);
  }
  public void onFinish() {}
}.start();

Best regards.

Upvotes: 11

Views: 31036

Answers (3)

Peter Ajtai
Peter Ajtai

Reputation: 57685

Take a look at android.widget.MediaController, it has a progress bar.

They use a handler that recursively calls itself if appropriate. You can set the delay to however often you want the progress bar updated.

Note that the controller can be shown or hidden as well as dragged by the user, and - of course - the video can stop. These are the reasons for the various checks (!mDragging && mShowing && mVideoView.isPlaying()) before another recursive call to update the bar.

protected Handler mHandler = new Handler()
{
    @Override
    public void handleMessage(Message msg)
    {
        int pos;
        switch (msg.what)
        {
            // ...

            case SHOW_PROGRESS:
                pos = setProgress();
                if (!mDragging && mShowing && mVideoView.isPlaying())
                {
                    msg = obtainMessage(SHOW_PROGRESS);
                    sendMessageDelayed(msg, 1000 - (pos % 1000));
                }
                break;

             // ...
        }
    }
};

To start it off use:

mHandler.sendEmptyMessage(SHOW_PROGRESS);

It will stop by itself, but you should cancel the last pending request using:

mHandler.removeMessages(SHOW_PROGRESS);

Upvotes: 11

JRaymond
JRaymond

Reputation: 11782

Personally, I start off a Thread that checks getCurrentPosition() every 200ms or so until the onCompletion() event gets fired off:

private class MediaObserver implements Runnable {
  private AtomicBoolean stop = new AtomicBoolean(false);

  public void stop() {
    stop.set(true);
  }

  @Override
  public void run() {
    while (!stop.get()) {
      progress.setProgress(mediaPlayer.getCurrentPosition());
      Thread.sleep(200);
    }
  }
}

private MediaObserver observer = null;

public void runMedia() {
  mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener{
    @Override
    public void onCompletion(MediaPlayer mPlayer) {
      observer.stop();
      progress.setProgress(mPlayer.getCurrentPosition());
    }
  });
  observer = new MediaObserver();
  mediaPlayer.start();
  new Thread(observer).start();
}

Upvotes: 23

Fedor Tsyganov
Fedor Tsyganov

Reputation: 1002

The most efficient way is to use JRaymond's answer and EventBus

private class MediaObserver implements Runnable {
    private AtomicBoolean stop = new AtomicBoolean(false);
    public void stop() {
        stop.set(true);
    }

    @Override public void run() {
        while (!stop.get()) {
            try {
              if (player.isPlaying())
                 sendMsgToUI(player.getCurrentPosition(),
                             player.getDuration());
            } catch (Exception e){e.printStackTrace();}
            try { 
              Thread.sleep(100);
            } catch (InterruptedException e) { e.printStackTrace(); }
        }
    }
}

private MediaObserver observer = null;

public void runMedia() {
    observer = new MediaObserver();
    new Thread(observer).start();
}

//handles all the background threads things for you
private void sendMsgToUI(int position) {
    ChangingEvent event = new ChangingEvent(position);
    EventBus.getDefault().post(event);
}

ChangingEvent class would look something like that:

public class ChangingEvent {
  private int position;

  public ChangingEvent(int position) {
      this.position= position;
  }

  public int getPosition() {
      return position;
  }
}

and in your Activity or Fragment all you have to do is

class YouClass extends Activity {
  private EventBus eventBus = EventBus.getDefault();
}

@Override protected void onCreate(Bundle savedInstanceState) {
    //your code
    eventBus.register(this);
}
//eventbus that updates UI
public void onEventMainThread(ChangingEvent event) {
    //seekbar or any other ui element
    seekBar.setProgress(event.getPosition());
}

Upvotes: 3

Related Questions