2012-04-03 4 views
8

Ist dies der richtige Weg, um eine ProgressBar beim Abspielen von Media zu aktualisieren? Ich dachte, es würde einen Rückruf im MediaPlayer geben, aber ich konnte ihn nicht finden.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(); 

Mit freundlichen Grüßen.

Antwort

10

Werfen Sie einen Blick auf android.widget.MediaController, es hat einen Fortschrittsbalken.

Sie verwenden einen Handler, der sich gegebenenfalls rekursiv selbst aufruft. Sie können die Verzögerung so einstellen, wie oft der Fortschrittsbalken aktualisiert werden soll.

Beachten Sie, dass der Controller kann angezeigt oder ausgeblendet sowie vom Benutzer gezogen werden, und - natürlich - kann das Video anhalten. Dies sind die Gründe für die verschiedenen Überprüfungen (!mDragging && mShowing && mVideoView.isPlaying()) vor einem weiteren rekursiven Aufruf zum Aktualisieren der Leiste.

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; 

      // ... 
     } 
    } 
}; 

es Um beginnen Nutzung:

mHandler.sendEmptyMessage(SHOW_PROGRESS); 

Es selbst zu stoppen, aber Sie sollten die letzte ausstehende Anforderung mit Abbrechen:

mHandler.removeMessages(SHOW_PROGRESS); 
+1

Danke, genau, wonach ich gesucht habe. – pouzzler

+0

@pouzzler - Gern geschehen! Ein Blick auf die MediaController-Klasse ist ideal, um Ihnen Ideen für die Erstellung eines benutzerdefinierten Controllers zu geben. –

+0

Zweite Verbindung ist wegen einer DMCA-Takedown gegangen: https://github.com/OESF/OHA-Android-4.0.1_r1.0 – astromme

16

Ich persönlich einen Thread beginnen, die getCurrentPosition() alle 200ms überprüft oder so, bis die onCompletion() Ereignis abgefeuert wird:

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

Der Timer blockiert nicht die Benutzeroberfläche so nehme ich es in einem anderen Thread ist . Ich nehme an, es ist dasselbe. Ich wünschte, ich wäre intelligent genug, um diese Dinge herauszufinden. – pouzzler

+0

@pouzzler Countdown-Timer wird in einem anderen Thread ausgeführt. Der einzige Unterschied besteht darin, dass der tatsächliche Fortschritt nicht verwendet wird. Ich werde ein Gewinde Beispiel schreiben – JRaymond

+0

ah keine Notwendigkeit, ich verstehe es. Danke :) – pouzzler

1

Der effizienteste Weg zu verwenden ist JRaymonds Antwort und 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 Klasse würde so ähnlich aussehen:

public class ChangingEvent { 
    private int position; 

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

    public int getPosition() { 
     return position; 
    } 
} 

und in Ihrer Aktivität oder Fragment alles, was Sie tun müssen, ist

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

Ich mag diesen Ansatz, aber ich glaube, Sie haben vergessen, Schleife hinzuzufügen/während das macht run() mehr als nur einmal ausgeführt werden –

+0

Oh, ja, danke, dass du es bemerkt hast - ich werde es jetzt korrigieren. –