Die Benutzeroberfläche des Players

Ein Player ist die Komponente Ihrer App, die die Wiedergabe von Medienelementen ermöglicht. Die Media3-Benutzeroberfläche Player definiert einen Überblick über Funktionen, die in der Regel von einem Player verarbeitet werden. Dazu gehören:

  • Auswirkungen auf die Wiedergabesteuerung, z. B. Wiedergabe, Pausieren und Suchen
  • Abfragen von Eigenschaften der gerade abgespielten Medien, z. B. der Wiedergabeposition
  • Playlists/Warteschlangen mit Medienelementen verwalten
  • Wiedergabeeigenschaften wie Zufallsmix, Wiederholung, Geschwindigkeit und Lautstärke konfigurieren
  • Video auf dem Bildschirm rendern

Media3 bietet auch eine Implementierung der Player-Schnittstelle namens ExoPlayer.

Eine gemeinsame Schnittstelle zwischen Komponenten

Die Player-Schnittstelle wird in mehreren Komponenten in Media3 implementiert, z. B.:

Komponente Beschreibung und Verhaltensnotizen
ExoPlayer Eine Mediaplayer-API und die Standardimplementierung der Player-Schnittstelle.
MediaController Interagiert mit einem MediaSession, um Wiedergabebefehle zu senden. Wenn sich deine Player und MediaSession in einer Service befinden, die von der Activity oder Fragment getrennt ist, in der sich die Benutzeroberfläche deines Players befindet, kannst du deine MediaController als Player für deine PlayerView-Benutzeroberfläche zuweisen. Aufrufe von Wiedergabe- und Playlist-Methoden werden über deinen MediaSession an deinen Player gesendet.
MediaBrowser Zusätzlich zu den Funktionen eines MediaController interagiert es mit einem MediaLibrarySession, um verfügbare Medieninhalte zu durchsuchen.
ForwardingPlayer Eine Player-Implementierung, die Methodenaufrufe an eine andere Player weiterleitet. Mit dieser Klasse können Sie bestimmte Vorgänge unterdrücken oder ändern, indem Sie die entsprechenden Methoden überschreiben.
SimpleBasePlayer Eine Player-Implementierung, die die Anzahl der zu implementierenden Methoden auf ein Minimum reduziert. Hilfreich, wenn du einen benutzerdefinierten Player verwendest, den du mit einer MediaSession verbinden möchtest.
CastPlayer Eine Player-Implementierung, die mit einer Cast-Empfänger-App kommuniziert. Das Verhalten hängt von der zugrunde liegenden Cast-Sitzung ab.

Auch wenn eine MediaSession die Player-Schnittstelle nicht implementiert, ist beim Erstellen eine Player erforderlich. Er dient dazu, anderen Prozessen oder Threads Zugriff auf die Player zu gewähren.

Media3-Wiedergabearchitektur

Wenn du Zugriff auf eine Player hast, solltest du ihre Methoden direkt aufrufen, um Wiedergabebefehle zu senden. Du kannst für deine Wiedergabe werben und externen Quellen die Wiedergabesteuerung gewähren, indem du eine MediaSession implementierst. Diese externen Quellen implementieren eine MediaController, die die Verbindung zu einer Mediensitzung und das Senden von Wiedergabebefehlsanfragen vereinfacht.

Wenn Sie Medien im Hintergrund abspielen möchten, müssen Sie Ihre Mediensitzung und Ihren Player in einem MediaSessionService oder MediaLibraryService unterbringen, der als Vordergrunddienst ausgeführt wird. So kannst du deinen Player von der Aktivität in deiner App trennen, die die Benutzeroberfläche für die Wiedergabesteuerung enthält. Möglicherweise müssen Sie dazu einen Mediacontroller verwenden.

Ein Diagramm, das zeigt, wie Media3-Wiedergabekomponenten in die Architektur einer Medien-App passen
Abbildung 1: Die Player-Schnittstelle spielt eine wichtige Rolle in der Architektur von Media3.

Player-Status

Der Status eines Mediaplayers, der die Player-Benutzeroberfläche implementiert, besteht hauptsächlich aus vier Kategorien von Informationen:

  1. Wiedergabestatus
  2. Playlist mit Medienelementen
  3. Wiedergabe-/Pause-Eigenschaften, z. B.:
    • playWhenReady: Gibt an, ob Medien nach Möglichkeit abgespielt oder angehalten bleiben sollen
    • Grund für die Unterdrückung der Wiedergabe: Angabe dazu, warum die Wiedergabe unterdrückt wird, falls zutreffend, auch wenn playWhenReady = true ist.
    • isPlaying: Gibt an, ob der Player gerade etwas wiedergibt. Der Wert ist nur true, wenn der Wiedergabestatus STATE_READY, playWhenReady true und die Wiedergabe nicht unterdrückt wird.
  4. Wiedergabeposition, einschließlich:

Außerdem bietet die Player-Benutzeroberfläche Zugriff auf die verfügbaren Titel, Medienmetadaten, Wiedergabegeschwindigkeit, Lautstärke und andere zusätzliche Eigenschaften der Wiedergabe.

Auf Änderungen achten

Mit einem Player.Listener können Sie auf Änderungen in einem Player achten. Weitere Informationen zum Erstellen und Verwenden eines Listeners findest du in der ExoPlayer-Dokumentation zu Player-Ereignissen.

Die Listener-Benutzeroberfläche enthält keine Rückrufe, um den normalen Wiedergabeverlauf zu verfolgen. Wenn du den Wiedergabefortschritt kontinuierlich überwachen möchtest, z. B. um eine Fortschrittsanzeige einzurichten, solltest du die aktuelle Position in regelmäßigen Abständen abfragen.

Kotlin

val handler = Handler(Looper.getMainLooper())
fun checkPlaybackPosition(delayMs: Long): Boolean =
  handler.postDelayed(
    {
      val currentPosition = player.currentPosition
      // Update UI based on currentPosition
      checkPlaybackPosition(delayMs)
    },
    delayMs)

Java

Handler handler = new Handler(Looper.getMainLooper());
boolean checkPlaybackPosition(long delayMs) {
    return handler.postDelayed(() -> {
        long currentPosition = player.getCurrentPosition();
        // Update UI based on currentPosition
        checkPlaybackPosition(delayMs);
    }, delayMs);
}

Wiedergabe steuern

Die Player-Oberfläche bietet viele Möglichkeiten, den Status zu ändern und die Wiedergabe zu steuern:

Benutzerdefinierte Player-Implementierungen

Wenn du einen benutzerdefinierten Player erstellen möchtest, kannst du den in Media3 enthaltenen SimpleBasePlayer erweitern. Diese Klasse bietet eine Basisimplementierung der Player-Schnittstelle, um die Anzahl der zu implementierenden Methoden auf ein Minimum zu reduzieren.

Überschreiben Sie zuerst die Methode getState(). Diese Methode sollte beim Aufrufen den aktuellen Spielerstatus angeben, einschließlich:

  • Verfügbare Befehle
  • Wiedergabeeigenschaften, z. B. ob der Player mit der Wiedergabe beginnen soll, wenn der Wiedergabestatus STATE_READY ist, der Index des aktuell wiedergegebenen Medienelements und die Wiedergabeposition innerhalb des aktuellen Elements

Kotlin

class CustomPlayer : SimpleBasePlayer(looper) {
  override fun getState(): State {
    return State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build()
  }
}

Java

public class CustomPlayer extends SimpleBasePlayer {
  public CustomPlayer(Looper looper) {
    super(looper);
  }

  @Override
  protected State getState() {
    return new State.Builder()
      .setAvailableCommands(...) // Set which playback commands the player can handle
      // Configure additional playback properties
      .setPlayWhenReady(true, PLAY_WHEN_READY_CHANGE_REASON_USER_REQUEST)
      .setCurrentMediaItemIndex(0)
      .setContentPositionMs(0)
      .build();
  }
}

SimpleBasePlayer erzwingt, dass State mit einer gültigen Kombination von Statuswerten erstellt wird. Außerdem werden Listener verwaltet und Listener über Statusänderungen informiert. Wenn Sie einen Statusupdate manuell auslösen möchten, rufen Sie invalidateState() an.

Neben der getState()-Methode müssen Sie nur Methoden implementieren, die für Befehle verwendet werden, die dein Spieler als verfügbar erklärt. Suchen Sie die überschreibbare Handlermethode, die der Funktion entspricht, die Sie implementieren möchten. Sie können beispielsweise die Methode handleSeek() überschreiben, um Vorgänge wie COMMAND_SEEK_IN_CURRENT_MEDIA_ITEM und COMMAND_SEEK_TO_NEXT_MEDIA_ITEM zu unterstützen.