2012-04-03 19 views
8

¿Es esta la forma correcta de actualizar una ProgressBar cuando se reproducen medios? Pensé que habría una devolución de llamada en MediaPlayer, pero no pude encontrarlo.MediaPlayer, ProgressBar

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(); 

Recuerdos.

Respuesta

10

Tome un vistazo a android.widget.MediaController, tiene una barra de progreso.

Utilizan un controlador que se llama recursivamente si es apropiado. Puede configurar el retraso a la frecuencia con la que quiera que se actualice la barra de progreso.

Tenga en cuenta que el controlador se puede mostrar u ocultar, así como también puede ser arrastrado por el usuario, y, por supuesto, el video puede detenerse. Estos son los motivos de las diversas comprobaciones (!mDragging && mShowing && mVideoView.isPlaying()) antes de otra llamada recursiva para actualizar la barra.

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; 

      // ... 
     } 
    } 
}; 

para iniciarlo fuera de uso:

mHandler.sendEmptyMessage(SHOW_PROGRESS); 

Se detendrá por sí mismo, sino que debe cancelar la última solicitud pendiente usando:

mHandler.removeMessages(SHOW_PROGRESS); 
+1

Gracias, precisamente, lo que estaba buscando. – pouzzler

+0

@pouzzler - ¡De nada! Ver la clase MediaController es excelente para darle ideas sobre cómo crear un controlador personalizado. –

+0

Segundo enlace se ha ido debido a un derribo de DMCA: https://github.com/OESF/OHA-Android-4.0.1_r1.0 – astromme

16

Personalmente, a empezar un hilo que comprueba getCurrentPosition() cada 200 ms o menos hasta que el evento onCompletion() se disparó:

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(); 
} 
+0

El temporizador no bloquea la interfaz de usuario, así que supongo que es en otro hilo . Entonces supongo que es lo mismo. Desearía ser lo suficientemente inteligente como para resolver estas cosas. – pouzzler

+0

@pouzzler El temporizador de cuenta regresiva se ejecuta en otro subproceso, la única diferencia es que no utiliza el progreso real. Voy a escribir un ejemplo enhebrado – JRaymond

+0

ah no es necesario, lo entiendo. Gracias :) – pouzzler

1

La manera más eficaz es utilizar Respuesta de JRaymond y 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); 
} 

clase ChangingEvent se vería algo así:

public class ChangingEvent { 
    private int position; 

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

    public int getPosition() { 
     return position; 
    } 
} 

y en su actividad o fragmento de todo lo que tiene que hacer es

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()); 
} 
+0

Me gusta este enfoque, pero creo que olvidó agregar loop/while que hace que run() se ejecuta más de una vez –

+0

Oh, sí, gracias por notar eso, lo corregiré ahora. –