2012-04-03 18 views
8

È questo il modo corretto di aggiornare una barra di avanzamento durante la riproduzione di Media? Ho pensato che ci sarebbe stata una richiamata in MediaPlayer, ma non riuscivo a trovarla.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(); 

Cordiali saluti.

risposta

10

Date un'occhiata a android.widget.MediaController, ha una barra di avanzamento.

Utilizzano un gestore che ricorsivamente chiama se stesso. È possibile impostare il ritardo su, tuttavia, spesso si desidera aggiornare la barra di avanzamento.

Si noti che il controller può essere mostrato o nascosto e trascinato dall'utente, e - ovviamente - il video può fermarsi. Questi sono i motivi dei vari controlli (!mDragging && mShowing && mVideoView.isPlaying()) prima di un'altra chiamata ricorsiva per aggiornare 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; 

      // ... 
     } 
    } 
}; 

per avviarlo fuori uso:

mHandler.sendEmptyMessage(SHOW_PROGRESS); 

Si fermerà da solo, ma si dovrebbe annullare l'ultima richiesta in sospeso utilizza:

mHandler.removeMessages(SHOW_PROGRESS); 
+1

Grazie, appunto, quello che stavo cercando. – pouzzler

+0

@pouzzler - Prego! L'esame della classe MediaController è ottimo per darti idee su come creare un controller personalizzato. –

+0

Il secondo link è andato a causa di una rimozione DMCA: https://github.com/OESF/OHA-Android-4.0.1_r1.0 – astromme

16

Personalmente, ho Iniziamo un filo che controlla getCurrentPosition() ogni 200ms o giù di lì fino a quando l'evento viene onCompletion() sparò:

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

Il timer non blocca l'interfaccia utente quindi suppongo che sia in un altro thread . Quindi suppongo sia lo stesso. Vorrei essere abbastanza intelligente da capire queste cose. – pouzzler

+0

@pouzzler Il conto alla rovescia viene eseguito in un altro thread, l'unica differenza è che non utilizza il progresso effettivo. Scriverò un esempio filettato – JRaymond

+0

ah non ce n'è bisogno, ho capito. Grazie :) – pouzzler

1

Il modo più efficace è quello di utilizzare JRaymond's answer e 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); 
} 

classe ChangingEvent sarebbe simile a quello:

public class ChangingEvent { 
    private int position; 

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

    public int getPosition() { 
     return position; 
    } 
} 

e nella vostra attività o Frammento tutto quello che dovete fare è

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

Mi piace questo approccio, ma penso che hai dimenticato di aggiungere loop/while che rende run() in esecuzione più di una volta –

+0

Oh, sì, grazie per averlo notato - lo correggerò ora. –