Einfache Mediaplayer-App mit Media3 ExoPlayer erstellen

Jetpack Media3 definiert eine Player-Schnittstelle, die grundlegende Funktionen für die Wiedergabe von Video- und Audiodateien beschreibt. ExoPlayer ist die Standardimplementierung dieser Schnittstelle in Media3. Wir empfehlen die Verwendung von ExoPlayer, da es eine umfassende Reihe von Funktionen bietet, die die meisten Wiedergabeanwendungsfälle abdecken, und an alle zusätzlichen Anwendungsfälle angepasst werden kann. ExoPlayer abstrahiert auch die Geräte- und Betriebssystemfragmentierung, sodass Ihr Code im gesamten Android-Ökosystem konsistent funktioniert. ExoPlayer umfasst:

Auf dieser Seite werden einige der wichtigsten Schritte beim Erstellen einer Wiedergabe-App beschrieben. Weitere Informationen finden Sie in unseren vollständigen Leitfäden zu Media3 ExoPlayer.

Erste Schritte

Fügen Sie zuerst eine Abhängigkeit von den ExoPlayer-, UI- und Common-Modulen von Jetpack Media3 hinzu:

implementation "androidx.media3:media3-exoplayer:1.8.0"
implementation "androidx.media3:media3-ui:1.8.0"
implementation "androidx.media3:media3-common:1.8.0"

Je nach Anwendungsfall benötigen Sie möglicherweise auch zusätzliche Module aus Media3, z. B. exoplayer-dash, um Streams im DASH-Format abzuspielen.

Ersetzen Sie 1.8.0 durch die gewünschte Version der Bibliothek. Die aktuelle Version finden Sie in den Versionshinweisen.

Mediaplayer erstellen

Mit Media3 können Sie entweder die enthaltene Implementierung der Player-Schnittstelle, ExoPlayer, verwenden oder eine eigene benutzerdefinierte Implementierung erstellen.

ExoPlayer erstellen

Die einfachste Methode zum Erstellen einer ExoPlayer-Instanz ist folgende:

Kotlin

val player = ExoPlayer.Builder(context).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();

Sie können Ihren Media Player in der onCreate()-Lifecycle-Methode des Activity, Fragment oder Service erstellen, in dem er sich befindet.

Die Builder bietet eine Reihe von Anpassungsoptionen, die für Sie interessant sein könnten, z. B.:

Media3 bietet eine PlayerView-UI-Komponente, die Sie in die Layoutdatei Ihrer App einfügen können. Diese Komponente umfasst ein PlayerControlView für die Wiedergabesteuerung, ein SubtitleView für die Anzeige von Untertiteln und ein Surface für das Rendern von Videos.

Player vorbereiten

Füge einer Playlist Mediendateien für die Wiedergabe mit Methoden wie setMediaItem() und addMediaItem() hinzu. Rufen Sie dann prepare() auf, um mit dem Laden von Media zu beginnen und die erforderlichen Ressourcen abzurufen.

Sie sollten diese Schritte erst ausführen, wenn sich die App im Vordergrund befindet. Wenn sich dein Player in einem Activity oder Fragment befindet, bedeutet das, dass der Player in der onStart()-Lebenszyklusmethode auf API-Level 24 und höher oder in der onResume()-Lebenszyklusmethode auf API-Level 23 und niedriger vorbereitet wird. Für einen Spieler, der sich in einem Service befindet, können Sie ihn in onCreate() vorbereiten. Ein Beispiel für die Implementierung von Lebenszyklusmethoden finden Sie im ExoPlayer-Codelab.

Player steuern

Nachdem der Player vorbereitet wurde, können Sie die Wiedergabe steuern, indem Sie Methoden für den Player aufrufen, z. B.:

UI-Komponenten wie PlayerView oder PlayerControlView werden entsprechend aktualisiert, wenn sie an einen Player gebunden sind.

Spieler freigeben

Die Wiedergabe kann Ressourcen erfordern, die nur begrenzt verfügbar sind, z. B. Videodecoder. Daher ist es wichtig, release() für den Player aufzurufen, um Ressourcen freizugeben, wenn der Player nicht mehr benötigt wird.

Wenn sich der Player in einem Activity oder Fragment befindet, geben Sie ihn mit der onStop()-Lebenszyklusmethode auf API-Level 24 und höher oder mit der onPause()-Methode auf API-Level 23 und niedriger frei. Ein Spieler, der sich in einem Service befindet, kann in onDestroy() veröffentlicht werden. Ein Beispiel für die Implementierung von Lebenszyklusmethoden finden Sie im ExoPlayer-Codelab.

Wiedergabe mit einer Mediensitzung verwalten

Unter Android bieten Media Sessions eine standardisierte Möglichkeit, prozessübergreifend mit einem Mediaplayer zu interagieren. Wenn Sie eine Media Session mit Ihrem Player verbinden, können Sie die Medienwiedergabe extern bewerben und Wiedergabebefehle von externen Quellen empfangen, z. B. um die System-Mediensteuerung auf Mobilgeräten und Geräten mit großem Display zu integrieren.

Wenn Sie Mediensitzungen verwenden möchten, fügen Sie eine Abhängigkeit vom Media3-Sitzungsmodul hinzu:

implementation "androidx.media3:media3-session:1.8.0"

Media Session erstellen

So erstellen Sie ein MediaSession-Objekt nach der Initialisierung eines Players:

Kotlin

val player = ExoPlayer.Builder(context).build()
val mediaSession = MediaSession.Builder(context, player).build()

Java

ExoPlayer player = new ExoPlayer.Builder(context).build();
MediaSession mediaSession = new MediaSession.Builder(context, player).build();

Media3 synchronisiert den Status von Player automatisch mit dem Status von MediaSession. Das funktioniert mit jeder Player-Implementierung, einschließlich ExoPlayer, CastPlayer oder einer benutzerdefinierten Implementierung.

Anderen Clients die Kontrolle überlassen

Client-Apps können einen Media Controller implementieren, um die Wiedergabe Ihrer Media Session zu steuern. Wenn Sie diese Anfragen erhalten möchten, legen Sie beim Erstellen von MediaSession ein Callback-Objekt fest.

Wenn ein Controller eine Verbindung zu Ihrer Media Session herstellt, wird die Methode onConnect() aufgerufen. Anhand der bereitgestellten ControllerInfo können Sie entscheiden, ob Sie die Anfrage annehmen oder ablehnen. Ein Beispiel dafür finden Sie in der Media3 Session-Demo-App.

Nachdem eine Verbindung hergestellt wurde, kann ein Controller Wiedergabebefehle an die Sitzung senden. Die Session leitet diese Befehle dann an den Player weiter. Wiedergabe- und Playlist-Befehle, die in der Player-Schnittstelle definiert sind, werden automatisch von der Session verarbeitet.

Mit anderen Callback-Methoden können Sie beispielsweise Anfragen für benutzerdefinierte Wiedergabebefehle und Änderungen an der Playlist verarbeiten. Diese Callbacks enthalten ebenfalls ein ControllerInfo-Objekt, sodass Sie die Zugriffssteuerung für jede Anfrage einzeln festlegen können.

Medien im Hintergrund abspielen

Wenn Sie Medien weiter abspielen möchten, wenn Ihre App nicht im Vordergrund ist, z. B. um Musik, Hörbücher oder Podcasts abzuspielen, auch wenn der Nutzer Ihre App nicht geöffnet hat, sollten Ihre Player und MediaSession in einem Dienst im Vordergrund gekapselt werden. Media3 bietet hierfür die MediaSessionService-Schnittstelle.

MediaSessionService implementieren

Erstellen Sie eine Klasse, die MediaSessionService erweitert, und instanziieren Sie MediaSession in der Lifecycle-Methode onCreate().

Kotlin

class PlaybackService : MediaSessionService() {
    private var mediaSession: MediaSession? = null

    // Create your Player and MediaSession in the onCreate lifecycle event
    override fun onCreate() {
        super.onCreate()
        val player = ExoPlayer.Builder(this).build()
        mediaSession = MediaSession.Builder(this, player).build()
    }

    // Remember to release the player and media session in onDestroy
    override fun onDestroy() {
        mediaSession?.run {
            player.release()
            release()
            mediaSession = null
        }
        super.onDestroy()
    }
}

Java

public class PlaybackService extends MediaSessionService {
    private MediaSession mediaSession = null;

    @Override
    public void onCreate() {
        super.onCreate();
        ExoPlayer player = new ExoPlayer.Builder(this).build();
        mediaSession = new MediaSession.Builder(this, player).build();
    }

    @Override
    public void onDestroy() {
        mediaSession.getPlayer().release();
        mediaSession.release();
        mediaSession = null;
        super.onDestroy();
    }
}

Fügen Sie in Ihrem Manifest die Klasse Service mit einem Intent-Filter MediaSessionService hinzu und fordern Sie die Berechtigung FOREGROUND_SERVICE an, um einen Vordergrunddienst auszuführen:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaSessionService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Überschreiben Sie schließlich in der von Ihnen erstellten Klasse die Methode onGetSession(), um den Clientzugriff auf Ihre Media Session zu steuern. Gib MediaSession zurück, um die Verbindungsanfrage anzunehmen, oder null, um sie abzulehnen.

Kotlin

// This example always accepts the connection request
override fun onGetSession(
    controllerInfo: MediaSession.ControllerInfo
): MediaSession? = mediaSession

Java

@Override
public MediaSession onGetSession(MediaSession.ControllerInfo controllerInfo) {
  // This example always accepts the connection request
  return mediaSession;
}

Verbindung zur Benutzeroberfläche herstellen

Da sich Ihre Mediensitzung jetzt in einem Service befindet, das sich vom Activity oder Fragment unterscheidet, in dem sich die Benutzeroberfläche des Players befindet, können Sie sie mit einem MediaController verknüpfen. Erstellen Sie in der Methode onStart() von Activity oder Fragment mit Ihrer Benutzeroberfläche einen SessionToken für Ihren MediaSession und verwenden Sie dann den SessionToken, um einen MediaController zu erstellen. Das Erstellen eines MediaController erfolgt asynchron.

Kotlin

override fun onStart() {
  val sessionToken = SessionToken(this, ComponentName(this, PlaybackService::class.java))
  val controllerFuture = MediaController.Builder(this, sessionToken).buildAsync()
  controllerFuture.addListener(
    {
        // Call controllerFuture.get() to retrieve the MediaController.
        // MediaController implements the Player interface, so it can be
        // attached to the PlayerView UI component.
        playerView.setPlayer(controllerFuture.get())
      },
    MoreExecutors.directExecutor()
  )
}

Java

@Override
public void onStart() {
  SessionToken sessionToken =
    new SessionToken(this, new ComponentName(this, PlaybackService.class));
  ListenableFuture<MediaController> controllerFuture =
    new MediaController.Builder(this, sessionToken).buildAsync();
  controllerFuture.addListener(() -> {
    // Call controllerFuture.get() to retrieve the MediaController.
    // MediaController implements the Player interface, so it can be
    // attached to the PlayerView UI component.
    playerView.setPlayer(controllerFuture.get());
  }, MoreExecutors.directExecutor())
}

MediaController implementiert die Player-Schnittstelle, sodass Sie dieselben Methoden wie play() und pause() verwenden können, um die Wiedergabe zu steuern. Wie bei anderen Komponenten müssen Sie die MediaController freigeben, wenn sie nicht mehr benötigt wird, z. B. in der onStop()-Lifecycle-Methode eines Activity, indem Sie MediaController.releaseFuture() aufrufen.

Benachrichtigung veröffentlichen

Für Dienste im Vordergrund ist es erforderlich, dass sie eine Benachrichtigung veröffentlichen, während sie aktiv sind. Bei einer MediaSessionService wird automatisch eine MediaStyle-Benachrichtigung in Form einer MediaNotification erstellt. Wenn Sie eine benutzerdefinierte Benachrichtigung bereitstellen möchten, erstellen Sie ein MediaNotification.Provider mit DefaultMediaNotificationProvider.Builder oder erstellen Sie eine benutzerdefinierte Implementierung der Anbieterschnittstelle. Fügen Sie Ihren Anbieter mit setMediaNotificationProvider zu Ihrem MediaSession hinzu.

Werbung für Ihre Inhaltsbibliothek

Eine MediaLibraryService baut auf einer MediaSessionService auf, indem Client-Apps die von Ihrer App bereitgestellten Medieninhalte durchsuchen können. Client-Apps implementieren eine MediaBrowser, um mit Ihrer MediaLibraryService zu interagieren.

Die Implementierung von MediaLibraryService ähnelt der Implementierung von MediaSessionService. Der Unterschied besteht darin, dass Sie in onGetSession() ein MediaLibrarySession anstelle eines MediaSession zurückgeben sollten. Im Vergleich zu einem MediaSession.Callback enthält das MediaLibrarySession.Callback zusätzliche Methoden, mit denen ein Browserclient die von Ihrem Bibliotheksdienst angebotenen Inhalte durchsuchen kann.

Deklarieren Sie wie bei MediaSessionService die MediaLibraryService in Ihrem Manifest und fordern Sie die Berechtigung FOREGROUND_SERVICE an, um einen Dienst im Vordergrund auszuführen:

<service
    android:name=".PlaybackService"
    android:foregroundServiceType="mediaPlayback"
    android:exported="true">
    <intent-filter>
        <action android:name="androidx.media3.session.MediaLibraryService"/>
        <action android:name="android.media.browse.MediaBrowserService"/>
    </intent-filter>
</service>

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

Das Beispiel oben enthält einen Intent-Filter für MediaLibraryService und zur Abwärtskompatibilität auch für MediaBrowserService. Der zusätzliche Intent-Filter ermöglicht es Client-Apps, die die MediaBrowserCompat API verwenden, Ihre Service zu erkennen.

Mit einem MediaLibrarySession können Sie Ihre Inhaltsbibliothek in einer Baumstruktur mit einem einzelnen Stammverzeichnis MediaItem bereitstellen. Jedes MediaItem im Baum kann beliebig viele untergeordnete MediaItem-Knoten haben. Sie können je nach Anfrage der Client-App einen anderen Stamm oder eine andere Struktur bereitstellen. Der Baum, den Sie an einen Client zurückgeben, der eine Liste empfohlener Media-Elemente sucht, enthält möglicherweise nur den Stammknoten MediaItem und eine einzelne Ebene von untergeordneten MediaItem-Knoten. Der Baum, den Sie an eine andere Client-App zurückgeben, kann dagegen eine vollständigere Inhaltsbibliothek darstellen.

MediaLibrarySession erstellen

Eine MediaLibrarySession erweitert die MediaSession API um APIs zum Durchsuchen von Inhalten. Im Vergleich zum MediaSession-Callback werden dem MediaLibrarySession-Callback Methoden wie die folgenden hinzugefügt:

  • onGetLibraryRoot() wenn ein Client den Stamm MediaItem eines Inhaltsbaums anfordert
  • onGetChildren() wenn ein Client die untergeordneten Elemente eines MediaItem im Inhaltsbaum anfordert
  • onGetSearchResult() wenn ein Kunde Suchergebnisse aus dem Inhaltsbaum für eine bestimmte Anfrage anfordert.

Relevante Callback-Methoden enthalten ein LibraryParams-Objekt mit zusätzlichen Signalen zum Typ des Inhaltsbaums, für den sich eine Client-App interessiert.