Jetpack Media3 definiert eine Player
-Schnittstelle, die die grundlegenden 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 er eine umfassende Palette von Funktionen bietet, die die meisten Wiedergabeanwendungsfälle abdecken, und sich für zusätzliche Anwendungsfälle anpassen lässt. ExoPlayer abstrahiert auch die Geräte- und Betriebssystemfragmentierung, sodass Ihr Code im gesamten Android-System konsistent funktioniert. ExoPlayer umfasst Folgendes:
- Unterstützung für Playlists
- Unterstützung für eine Vielzahl von progressiven und adaptiven Streamingformaten
- Unterstützung sowohl der clientseitigen als auch der serverseitigen Anzeigenbereitstellung
- Unterstützung der DRM-geschützten Wiedergabe
Auf dieser Seite werden einige der wichtigsten Schritte zum Erstellen einer Wiedergabe-App beschrieben. Weitere Informationen findest du in unseren vollständigen Anleitungen zum 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.4.1" implementation "androidx.media3:media3-ui:1.4.1" implementation "androidx.media3:media3-common:1.4.1"
Je nach Anwendungsfall benötigst du möglicherweise auch zusätzliche Module von Media3, z. B. exoplayer-dash
, um Streams im DASH-Format abzuspielen.
Ersetzen Sie 1.4.1
durch die gewünschte Version der Bibliothek. Informationen zur neuesten Version finden Sie in den Versionshinweisen.
Mediaplayer erstellen
Bei Media3 können Sie entweder die enthaltene Implementierung der Player
-Schnittstelle (ExoPlayer
) verwenden oder Ihre eigene benutzerdefinierte Implementierung erstellen.
ExoPlayer erstellen
So erstellen Sie am einfachsten eine ExoPlayer
-Instanz:
Kotlin
val player = ExoPlayer.Builder(context).build()
Java
ExoPlayer player = new ExoPlayer.Builder(context).build();
Du kannst deinen Mediaplayer in der Lebenszyklusmethode onCreate()
des Activity
, Fragment
oder Service
erstellen, in dem er sich befindet.
Die Builder
enthält eine Reihe von Anpassungsoptionen, die Sie interessieren könnten, z. B.:
setAudioAttributes()
, um die Audiofokus-Verarbeitung zu konfigurierensetHandleAudioBecomingNoisy()
um das Wiedergabeverhalten zu konfigurieren, wenn ein Audioausgabegerät getrennt wirdsetTrackSelector()
zum Konfigurieren der Titelauswahl
Media3 bietet eine PlayerView
-UI-Komponente, die Sie in die Layoutdatei Ihrer App einbinden können. Diese Komponente enthält eine PlayerControlView
für die Wiedergabesteuerung, eine SubtitleView
für die Anzeige von Untertiteln und eine Surface
für das Rendern von Video.
Player vorbereiten
Fügen Sie einer Playlist Medienelemente zur Wiedergabe mit Methoden wie setMediaItem()
und addMediaItem()
hinzu.
Rufe dann prepare()
auf, um mit dem Laden der Medien zu beginnen und die erforderlichen Ressourcen abzurufen.
Sie sollten diese Schritte nicht ausführen, bevor die App im Vordergrund ausgeführt wird. Wenn sich dein Player in einem Activity
oder Fragment
befindet, musst du ihn mit der onStart()
-Lebenszyklusmethode auf API-Level 24 und höher oder der onResume()
-Lebenszyklusmethode auf API-Level 23 und niedriger vorbereiten. Für einen Spieler in einer Service
kannst du ihn in onCreate()
vorbereiten.
Player steuern
Nachdem der Player vorbereitet wurde, kannst du die Wiedergabe durch Aufrufen der folgenden Methoden im Player steuern:
play()
undpause()
zum Starten und Pausieren der WiedergabeseekTo()
, um zu einer Position im aktuellen Medienelement zu springenseekToNextMediaItem()
undseekToPreviousMediaItem()
, um durch die Playlist zu navigieren
UI-Komponenten wie PlayerView
oder PlayerControlView
werden entsprechend aktualisiert, wenn sie an einen Spieler gebunden sind.
Spieler freigeben
Für die Wiedergabe können Ressourcen benötigt werden, die nur begrenzt verfügbar sind, z. B. Videodekoder. Daher ist es wichtig, release()
auf dem Player aufzurufen, um Ressourcen freizugeben, wenn der Player nicht mehr benötigt wird.
Wenn sich dein Player in einem Activity
oder Fragment
befindet, veröffentliche ihn mit der onStop()
-Lebenszyklusmethode auf API-Level 24 und höher oder der onPause()
-Methode auf API-Level 23 und niedriger. Wenn sich ein Spieler in einer Service
befindet, kannst du ihn in onDestroy()
veröffentlichen.
Wiedergabe mit einer Mediensitzung verwalten
Unter Android bieten Mediensitzungen eine standardisierte Möglichkeit, über Prozessgrenzen hinweg mit einem Mediaplayer zu interagieren. Wenn du eine Mediensitzung mit deinem Player verbindest, kannst du deine Medienwiedergabe extern bewerben und Wiedergabebefehle von externen Quellen empfangen. So kannst du sie beispielsweise in die Systemmediensteuerung auf Mobilgeräten und Geräten mit großem Bildschirm einbinden.
Um Mediensitzungen zu verwenden, fügen Sie eine Abhängigkeit für das Media3-Sitzungsmodul hinzu:
implementation "androidx.media3:media3-session:1.4.1"
Mediensitzung erstellen
So erstellst du eine MediaSession
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 der Player
automatisch mit dem Status der MediaSession
. Das funktioniert mit jeder Player
-Implementierung, einschließlich ExoPlayer
, CastPlayer
oder einer benutzerdefinierten Implementierung.
Anderen Kunden Kontrolle gewähren
Client-Apps können einen Mediencontroller implementieren, um die Wiedergabe der Mediensitzung zu steuern. Damit Sie diese Anfragen erhalten, müssen Sie beim Erstellen von MediaSession
ein Callback-Objekt festlegen.
Wenn ein Controller eine Verbindung zu deiner Mediensitzung herstellen möchte, wird die Methode onConnect()
aufgerufen. Anhand des bereitgestellten ControllerInfo
kannst du entscheiden, ob du die Anfrage akzeptieren oder ablehnen möchtest. Ein Beispiel dafür findest du in der Media3 Session-Demo-App.
Sobald die Verbindung hergestellt ist, kann ein Controller Wiedergabebefehle an die Sitzung senden. Die Sitzung delegiert diese Befehle dann an den Player. Wiedergabe- und Playlistbefehle, die in der Player
-Benutzeroberfläche definiert sind, werden automatisch von der Sitzung verarbeitet.
Mit anderen Rückrufmethoden kannst du beispielsweise Anfragen für benutzerdefinierte Wiedergabebefehle und Änderungen an der Playlist verarbeiten. Diese Callbacks enthalten ebenfalls ein ControllerInfo
-Objekt, damit du die Zugriffssteuerung für jede Anfrage einzeln festlegen kannst.
Medien im Hintergrund abspielen
Wenn Sie Medien auch dann weiter abspielen möchten, wenn Ihre App nicht im Vordergrund ist, z. B. Musik, Hörbücher oder Podcasts, auch wenn der Nutzer Ihre App nicht geöffnet hat, sollten Player
und MediaSession
in einem Dienst im Vordergrund gekapselt werden. Media3 stellt hierfür die MediaSessionService
-Schnittstelle bereit.
MediaSessionService
implementieren
Erstellen Sie eine Klasse, die MediaSessionService
erweitert, und instanziieren Sie MediaSession
in der Lebenszyklusmethode 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(); } }
Filtern Sie in Ihrem Manifest die Service
-Klasse mit einem MediaSessionService
-Intent und fordern Sie die Berechtigung FOREGROUND_SERVICE
zum Ausführen eines Dienstes im Vordergrund an:
<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 Mediensitzung 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 die Mediensitzung nun in einer Service
befindet, die von der Activity
oder Fragment
getrennt ist, in der sich die Benutzeroberfläche des Players befindet, kannst du sie mit einem MediaController
verknüpfen. Erstellen Sie in der onStart()
-Methode der Activity
oder Fragment
mit Ihrer UI eine SessionToken
für Ihre MediaSession
und verwenden Sie dann die SessionToken
, um eine 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
-Benutzeroberfläche. Du kannst also die Wiedergabe mit denselben Methoden wie play()
und pause()
steuern. Ähnlich wie bei anderen Komponenten müssen Sie die MediaController
freigeben, wenn sie nicht mehr benötigt wird, z. B. die onStop()
-Lebenszyklusmethode einer Activity
, indem Sie MediaController.releaseFuture()
aufrufen.
Benachrichtigungen veröffentlichen
Dienste im Vordergrund müssen eine Benachrichtigung veröffentlichen, während sie aktiv sind. Mit einer MediaSessionService
wird automatisch eine MediaStyle
-Benachrichtigung in Form einer MediaNotification
für Sie erstellt.
Wenn Sie eine benutzerdefinierte Benachrichtigung bereitstellen möchten, erstellen Sie eine MediaNotification.Provider
mit DefaultMediaNotificationProvider.Builder
oder eine benutzerdefinierte Implementierung der Anbieterschnittstelle. Fügen Sie Ihren Anbieter mit setMediaNotificationProvider
zu MediaSession
hinzu.
Werbung für deine Inhaltsbibliothek
Ein MediaLibraryService
baut auf einem MediaSessionService
auf und erlaubt Client-Apps, die von deiner App bereitgestellten Medieninhalte zu durchsuchen. Client-Apps implementieren eine MediaBrowser
, um mit deinem MediaLibraryService
zu interagieren.
Die Implementierung von MediaLibraryService
ähnelt der von MediaSessionService
, mit der Ausnahme, dass in onGetSession()
anstelle von MediaSession
ein MediaLibrarySession
zurückgegeben werden sollte. Im Vergleich zu einer MediaSession.Callback
enthält die MediaLibrarySession.Callback
zusätzliche Methoden, mit denen ein Browserclient die von deinem Bibliotheksservice angebotenen Inhalte aufrufen kann.
Ähnlich wie bei MediaSessionService
deklarieren Sie MediaLibraryService
in Ihrem Manifest und fordern 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 sowohl für MediaLibraryService
als auch für den alten MediaBrowserService
, um die Abwärtskompatibilität zu gewährleisten. Durch den zusätzlichen Intent-Filter können Clientanwendungen, die die MediaBrowserCompat
API verwenden, Ihre Service
erkennen.
Mit einem MediaLibrarySession
kannst du deine Inhaltsbibliothek in einer Baumstruktur mit einer einzelnen StammMediaItem
bereitstellen. Jeder MediaItem
im Baum kann beliebig viele untergeordnete MediaItem
-Knoten haben. Sie können je nach Anfrage der Client-App einen anderen Stamm oder einen anderen Baum bereitstellen. Beispielsweise enthält der Baum, den du einem Client zurückgibst, der nach einer Liste empfohlener Medienelemente sucht, möglicherweise nur den Stammknoten MediaItem
und eine einzige Ebene von untergeordneten Knoten MediaItem
, während der Baum, den du einer anderen Client-App zurückgibst, eine vollständigere Bibliothek mit Inhalten darstellt.
MediaLibrarySession
erstellen
Eine MediaLibrarySession
erweitert die MediaSession
API um APIs für die Inhaltssuche. Im Vergleich zum MediaSession
-Callback bietet der MediaLibrarySession
-Callback Methoden wie:
onGetLibraryRoot()
wird verwendet, wenn ein Client den StammMediaItem
eines Inhaltsbaums anfordertonGetChildren()
wird verwendet, wenn ein Client die untergeordneten Elemente einesMediaItem
im Inhaltsbaum anfordertonGetSearchResult()
wird verwendet, wenn ein Client Suchergebnisse aus dem Inhaltsbaum für eine bestimmte Suchanfrage anfordert
Relevante Rückrufmethoden enthalten ein LibraryParams
-Objekt mit zusätzlichen Signalen zur Art des Inhaltsbaums, für den sich eine Client-App interessiert.