Screenshot: Die YouTube-Android-App
ExoPlayer ist ein Medienplayer auf App-Ebene, der auf den Low-Level-Medien-APIs von Android aufbaut. ExoPlayer hat eine Reihe von Vorteilen gegenüber dem integrierten MediaPlayer in Android. Er unterstützt viele der gleichen Medienformate wie MediaPlayer sowie adaptive Formate, wie DASH und SmoothStreaming. ExoPlayer ist in hohem Maße anpassbar und erweiterbar, so dass er für viele erweiterte Anwendungsfälle geeignet ist. Es ist ein Open-Source-Projekt, das von Google-Apps verwendet wird, darunter YouTube und Google Play Movies & TV.
- Voraussetzungen
- Was Sie tun werden
- Was Sie benötigen
- Get the code
- Verzeichnisstruktur
- Importieren Sie das Ausgangsprojekt
- app/build.gradle
- Add ExoPlayer dependency
- player-lib/build.gradle
- Hinzufügen des PlayerView-Elements
- activity_player.xml
- PlayerActivity.java
- Erstellen eines ExoPlayers
- PlayerActivity.java
- Erstellen Sie ein Medienelement
- PlayerActivity.java
- Der Activity-Lebenszyklus ist ein gutes Beispiel
- PlayerActivity.java
- PlayerActivity.java
- PlayerActivity.java
- PlayerActivity.java
- Abschließende Vorbereitung
- PlayerActivity.java
- Audio abspielen
- Testen Sie den Aktivitätslebenszyklus
- Video abspielen
- PlayerActivity.java
- PlayerActivity.java
- Adaptive Titelauswahl
- PlayerActivity.java
- Erstellen eines adaptiven MediaItem
- PlayerActivity.java
- Andere adaptive Streaming-Formate
- Hören Sie zu
- PlayerActivity.java
- PlayerActivity.java
- PlayerActivity.java
- Registrieren Sie Ihren Listener
- PlayerActivity.java
- PlayerActivity.java
- Gehen Sie tiefer
- activity_player.xml
- activity_player.xml
- Anpassen des Verhaltens
- activity_player.xml
- Anpassen des Aussehens
- activity_player.xml
- custom_player_control_view.xml
- custom_player_control_view.xml
- Den Standardstil außer Kraft setzen
- activity_player.xml
- exo_player**_control_view.xml**
- Mehr erfahren
Voraussetzungen
- Moderate Kenntnisse der Android-Entwicklung und von Android Studio
Was Sie tun werden
- Erstellen Sie eine
SimpleExoPlayer
Instanz, die Medien aus einer Vielzahl von Quellen vorbereitet und abspielt. - Integrieren Sie ExoPlayer in den Aktivitätslebenszyklus der App, um die Hintergrund- und Vordergrundwiedergabe sowie die Wiederaufnahme der Wiedergabe in einer Einzel- oder Mehrfensterumgebung zu unterstützen.
- Verwenden Sie
MediaItem
s, um eine Wiedergabeliste zu erstellen. - Adaptive Videostreams abspielen, die die Medienqualität an die verfügbare Bandbreite anpassen.
- Ereignis-Listener registrieren, um den Wiedergabestatus zu überwachen und zeigen, wie Listener verwendet werden können, um die Qualität der Wiedergabe zu messen.
- Verwenden Sie standardmäßige ExoPlayer UI-Komponenten und passen Sie sie dann an den Stil Ihrer App an.
Was Sie benötigen
- Android Studio Version 3.5 oder höher
- Ein Android-Gerät mit JellyBean (4.1) oder höher, idealerweise mit Nougat (7.1) oder höher, da es mehrere Fenster unterstützt.
Get the code
Um loszulegen, laden Sie das Android Studio-Projekt herunter:
Download zip
Alternativ können Sie das GitHub-Repository klonen:
git clone https://github.com/googlecodelabs/exoplayer-intro.git
Verzeichnisstruktur
Beim Klonen oder Entpacken erhalten Sie einen Stammordner (exoplayer-intro
), der einen Ordner für jeden Schritt dieses Codelabs enthält, zusammen mit allen benötigten Ressourcen:
/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-00/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-01/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-02/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-03/PATH/TO/YOUR/FOLDER/exoplayer-intro/exoplayer-codelab-04
Die exoplayer-codelab-N
Ordner (wobei N
00
bis 04
ist) enthalten den gewünschten Endzustand jedes Schritts dieses Codelabs. Es handelt sich um eigenständige Android Studio Projekte, die jeweils importiert werden können.
Importieren Sie das Ausgangsprojekt
- Starten Sie Android Studio.
- Wählen Sie Datei > Neu > Projekt importieren*.*
- Importieren Sie das Ausgangsprojekt aus
exoplayer-codelab-00
.
Screenshot: Projektstruktur beim Importieren
Nach Abschluss des Builds sehen Sie zwei Module: das Modul app
(vom Typ Anwendung) und das Modul player-lib
(vom Typ Bibliothek). Das Modul app
ist eigentlich leer und enthält nur ein Manifest. Alles aus dem player-lib
-Modul wird zusammengeführt, wenn die App mithilfe einer Gradle-Abhängigkeit in app/build.gradle
gebaut wird.
app/build.gradle
dependencies { implementation project(":player-lib")}
Die Medienplayer-Aktivität befindet sich im player-lib
-Modul. Der Grund für die Aufbewahrung in einem separaten Bibliotheksmodul ist, dass Sie es für APKs für verschiedene Plattformen, wie z. B. Mobile und Android TV, freigeben können. Außerdem können Sie so die Vorteile von Funktionen wie Dynamic Delivery nutzen, mit denen Ihre Medienwiedergabefunktion nur dann installiert wird, wenn der Benutzer sie benötigt.
- Stellen Sie die App bereit und führen Sie sie aus, um zu prüfen, ob alles in Ordnung ist. Die App sollte den Bildschirm mit einem schwarzen Hintergrund ausfüllen.
Bildschirmfoto: Blank app running
Add ExoPlayer dependency
ExoPlayer ist ein Open-Source-Projekt, das auf GitHub gehostet wird. Jede Version wird über jCenter verteilt, das eines der Standard-Paket-Repositories ist, die von Android Studio und Gradle verwendet werden. Jede Version wird durch eine Zeichenkette mit dem folgenden Format eindeutig identifiziert:
com.google.android.exoplayer:exoplayer:rX.X.X
Sie können ExoPlayer zu Ihrem Projekt hinzufügen, indem Sie einfach seine Klassen und UI-Komponenten importieren. Es ist ziemlich klein, mit einem geschrumpften Fußabdruck von etwa 70 bis 300 kB, abhängig von den enthaltenen Funktionen und unterstützten Formaten. Die ExoPlayer-Bibliothek ist in Module aufgeteilt, damit Entwickler nur die Funktionen importieren können, die sie benötigen. Weitere Informationen über die modulare Struktur von ExoPlayer finden Sie unter Hinzufügen von ExoPlayer-Modulen.
- Öffnen Sie die
build.gradle
-Datei desplayer-lib
-Moduls. - Hängen Sie die folgenden Zeilen an den
dependencies
-Abschnitt an und synchronisieren Sie das Projekt.
player-lib/build.gradle
dependencies { implementation 'com.google.android.exoplayer:exoplayer-core:2.12.0'implementation 'com.google.android.exoplayer:exoplayer-dash:2.12.0'implementation 'com.google.android.exoplayer:exoplayer-ui:2.12.0'}
Hinzufügen des PlayerView-Elements
- Öffnen Sie die Layout-Ressourcendatei
activity_player.xml
aus dem Modulplayer-lib
. - Positionieren Sie den Cursor innerhalb des Elements
FrameLayout
. - Starten Sie die Eingabe von
<PlayerView
und lassen Sie Android Studio das ElementPlayerView
automatisch vervollständigen. - Verwenden Sie
match_parent
fürwidth
undheight
. - Deklarieren Sie die ID als
video_view
.
activity_player.xml
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
Im weiteren Verlauf bezeichnen Sie dieses UI-Element als die Videoansicht.
- In der
PlayerActivity
müssen Sie nun die Videoansicht finden, damit Sie sie in deronCreate
-Methode der Aktivität richtig einrichten können.
PlayerActivity.java
@Overrideprotected void onCreate(Bundle savedInstanceState) { playerView = findViewById(R.id.video_view);}
- Fügen Sie das
playerView
-Memberfeld zu IhrerPlayerActivity
-Klasse hinzu. Stellen Sie sicher, dass der Typ der AnsichtPlayerView
ist.
Hinweis: Verwenden Sie die Quick Fix-Funktion in Android Studio, um ein Mitgliedsfeld automatisch hinzuzufügen. Denken Sie daran, den Typ auf
PlayerView
zu setzen und nicht auf den Standard
View
Screenshot: Quick-Fix-Menü zum Erstellen eines Mitgliedsfeldes
Erstellen eines ExoPlayers
Um Streaming-Medien abzuspielen, benötigen Sie ein ExoPlayer
Objekt. Der einfachste Weg, ein solches zu erstellen, ist die Verwendung der Klasse SimpleExoPlayer.Builder
. Wie der Name schon sagt, verwendet diese das Builder-Muster, um eine SimpleExoPlayer
-Instanz zu erstellen.
SimpleExoPlayer
ist eine praktische, universelle Implementierung der ExoPlayer
-Schnittstelle.
Fügen Sie eine private Methode initializePlayer
hinzu, um Ihr SimpleExoPlayer
zu erstellen.
PlayerActivity.java
private SimpleExoPlayer player;private void initializePlayer() { player = new SimpleExoPlayer.Builder(this).build(); playerView.setPlayer(player);}
Erstellen Sie ein SimpleExoPlayer.Builder
unter Verwendung Ihres Kontexts und rufen Sie dann build
auf, um Ihr SimpleExoPlayer
-Objekt zu erstellen. Dieses wird dann player
zugewiesen, das Sie als Mitgliedsfeld deklarieren müssen. Anschließend verwenden Sie playerView.setPlayer
, um player
an die entsprechende Ansicht zu binden.
Erstellen Sie ein Medienelement
Ihr player
benötigt nun einen Inhalt zum Abspielen. Dazu erstellen Sie ein MediaItem
. Es gibt viele verschiedene Arten von MediaItem
, aber du beginnst mit der Erstellung einer MP3-Datei aus dem Internet.
Die einfachste Art, ein MediaItem
zu erstellen, ist die Verwendung von MediaItem.fromUri
, das den URI einer Mediendatei akzeptiert. Fügen Sie das MediaItem
mit player.setMediaItem
zu player
hinzu.
- Fügen Sie den folgenden Code zu
initializePlayer
hinzu:
PlayerActivity.java
private void initializePlayer() { MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.setMediaItem(mediaItem);}
Beachten Sie, dass R.string.media_url_mp3
als https://storage.googleapis.com/exoplayer-test-media-0/play.mp3 in strings.xml
definiert ist.
Der Activity-Lebenszyklus ist ein gutes Beispiel
Unser player
kann eine Menge Ressourcen beanspruchen, einschließlich Speicher, CPU, Netzwerkverbindungen und Hardware-Codecs. Viele dieser Ressourcen sind knapp bemessen, insbesondere bei Hardware-Codecs, von denen es vielleicht nur einen gibt. Es ist wichtig, dass Sie diese Ressourcen für andere Anwendungen freigeben, wenn Sie sie nicht verwenden, z. B. wenn Ihre Anwendung in den Hintergrund gestellt wird.
Mit anderen Worten: Der Lebenszyklus Ihres Players sollte an den Lebenszyklus Ihrer Anwendung gebunden sein. Um dies zu implementieren, müssen Sie die vier Methoden von PlayerActivity
außer Kraft setzen: onStart
, onResume
, onPause
und onStop
.
- Klicken Sie bei geöffnetem
PlayerActivity
auf das Menü „Code“ > Überschreiben Sie Methoden…. - Wählen Sie
onStart
,onResume
,onPause
undonStop
. - Initialisieren Sie den Player im
onStart
– oderonResume
-Callback, je nach API-Level.
PlayerActivity.java
@Overridepublic void onStart() { super.onStart(); if (Util.SDK_INT >= 24) { initializePlayer(); }}@Overridepublic void onResume() { super.onResume(); hideSystemUi(); if ((Util.SDK_INT < 24 || player == null)) { initializePlayer(); }}
Android API-Level 24 und höher unterstützt mehrere Fenster. Da Ihre Anwendung im geteilten Fenstermodus sichtbar, aber nicht aktiv sein kann, müssen Sie den Player in onStart
initialisieren. Android-API-Level 24 und niedriger erfordert, dass Sie so lange wie möglich warten, bis Sie Ressourcen abrufen, also warten Sie bis onResume
, bevor Sie den Player initialisieren.
- Fügen Sie die
hideSystemUi
-Methode hinzu.
PlayerActivity.java
@SuppressLint("InlinedApi")private void hideSystemUi() { playerView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LOW_PROFILE | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION);}
hideSystemUi
ist eine Hilfsmethode, die in onResume
aufgerufen wird und Ihnen ein Vollbildmodus ermöglicht.
- Freigeben Sie Ressourcen mit
releasePlayer
(das Sie kurz erstellen) inonPause
undonStop
.
PlayerActivity.java
@Overridepublic void onPause() { super.onPause(); if (Util.SDK_INT < 24) { releasePlayer(); }}@Overridepublic void onStop() { super.onStop(); if (Util.SDK_INT >= 24) { releasePlayer(); }}
Bei API-Level 24 und niedriger gibt es keine Garantie, dass onStop
aufgerufen wird, also müssen Sie den Player so früh wie möglich in onPause
freigeben. Ab API-Stufe 24 (mit der der Multi- und Split-Window-Modus eingeführt wurde) ist der Aufruf von onStop
garantiert. Im angehaltenen Zustand ist Ihre Aktivität noch sichtbar, also warten Sie mit der Freigabe des Players bis onStop
.
Sie müssen nun eine releasePlayer
Methode erstellen, die die Ressourcen des Players freigibt und ihn zerstört.
- Fügen Sie den folgenden Code zur Aktivität hinzu:
PlayerActivity.java
private boolean playWhenReady = true;private int currentWindow = 0;private long playbackPosition = 0;private void releasePlayer() { if (player != null) { playWhenReady = player.getPlayWhenReady(); playbackPosition = player.getCurrentPosition(); currentWindow = player.getCurrentWindowIndex(); player.release(); player = null; }}
Bevor Sie den Player freigeben und zerstören, speichern Sie die folgenden Informationen:
- Abspiel-/Pausenstatus mit
getPlayWhenReady
. - Aktuelle Wiedergabeposition mit
getCurrentPosition
. - Aktueller Fensterindex mit
getCurrentWindowIndex
. Weitere Informationen über Fenster finden Sie unter Zeitleiste.
Damit können Sie die Wiedergabe an der Stelle fortsetzen, an der der Benutzer aufgehört hat. Alles, was Sie tun müssen, ist, diese Zustandsinformationen bei der Initialisierung Ihres Players bereitzustellen.
Abschließende Vorbereitung
Alles, was Sie jetzt tun müssen, ist, die Zustandsinformationen, die Sie in releasePlayer
gespeichert haben, bei der Initialisierung Ihres Players bereitzustellen.
- Fügen Sie das Folgende zu
initializePlayer
hinzu:
PlayerActivity.java
private void initializePlayer() { player.setPlayWhenReady(playWhenReady); player.seekTo(currentWindow, playbackPosition); player.prepare();}
Hier ist, was passiert:
-
setPlayWhenReady
sagt dem Player, ob er mit dem Abspielen beginnen soll, sobald alle Ressourcen für die Wiedergabe erworben wurden. DaplayWhenReady
anfänglichtrue
ist, beginnt die Wiedergabe automatisch, wenn die App zum ersten Mal ausgeführt wird. -
seekTo
weist den Player an, eine bestimmte Position innerhalb eines bestimmten Fensters anzusteuern. SowohlcurrentWindow
als auchplaybackPosition
werden auf Null initialisiert, damit die Wiedergabe beim ersten Start der App von Anfang an beginnt. -
prepare
weist den Player an, alle für die Wiedergabe erforderlichen Ressourcen zu beschaffen.
Audio abspielen
Endlich sind Sie fertig! Starten Sie die App, um die MP3-Datei abzuspielen und das eingebettete Artwork zu sehen.
Screenshot: Die App spielt einen einzelnen Track ab.
Testen Sie den Aktivitätslebenszyklus
Testen Sie, ob die App in allen verschiedenen Zuständen des Aktivitätslebenszyklus funktioniert.
- Starten Sie eine andere App und bringen Sie Ihre App wieder in den Vordergrund. Wird sie an der richtigen Stelle fortgesetzt?
- Halten Sie die Anwendung an, und verschieben Sie sie in den Hintergrund und dann wieder in den Vordergrund. Bleibt sie im Pausenzustand, wenn sie im Hintergrund ist?
- Drehen Sie die App. Wie verhält sie sich, wenn du die Ausrichtung vom Hoch- ins Querformat und zurück änderst?
Video abspielen
Wenn du ein Video abspielen willst, ist es so einfach wie das Ändern des Medienelement-URIs in eine MP4-Datei.
- Ändern Sie die URI in der
initializePlayer
aufR.string.media_url_mp4
. - Starten Sie die App erneut und testen Sie das Verhalten, nachdem sie im Hintergrund läuft, auch mit Videowiedergabe.
PlayerActivity.java
private void initializePlayer() { MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); }
Das PlayerView
macht alles. Anstelle des Artworks wird das Video im Vollbildmodus gerendert.
Screenshot: Die App spielt das Video ab.
Du rockst! Sie haben soeben eine App für Vollbild-Medien-Streaming auf Android erstellt, komplett mit Lifecycle-Management, gespeichertem Status und UI-Steuerelementen!
Ihre aktuelle App spielt eine einzelne Mediendatei ab, aber was, wenn Sie mehr als eine Mediendatei nacheinander abspielen wollen? Dafür brauchen Sie eine Wiedergabeliste.
Wiedergabelisten können erstellt werden, indem Sie weitere MediaItem
s zu Ihrem player
mit addMediaItem
hinzufügen. Dies ermöglicht eine nahtlose Wiedergabe und die Pufferung wird im Hintergrund gehandhabt, so dass der Benutzer beim Wechseln von Medienelementen keinen Pufferungsspinner sieht.
- Fügen Sie den folgenden Code zu
initializePlayer
hinzu:
PlayerActivity.java
private void initializePlayer() { player.setMediaItem(mediaItem); // Existing code MediaItem secondMediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.addMediaItem(secondMediaItem); }
Prüfen Sie, wie sich die Player-Steuerungen verhalten. Sie können und verwenden, um in der Reihenfolge der Medienelemente zu navigieren.
Screenshot: Wiedergabesteuerung mit nächster und vorheriger Schaltfläche
Das ist ziemlich praktisch! Weitere Informationen finden Sie in der Entwicklerdokumentation zu Medienelementen und Wiedergabelisten sowie in diesem Artikel über die Wiedergabelisten-API.
Adaptives Streaming ist eine Technik für das Streaming von Medien, bei der die Qualität des Streams auf der Grundlage der verfügbaren Netzwerkbandbreite variiert wird. Auf diese Weise kann der Benutzer die Medien in der besten Qualität erleben, die seine Bandbreite zulässt.
In der Regel wird derselbe Medieninhalt in mehrere Tracks mit unterschiedlichen Qualitäten (Bitraten und Auflösungen) aufgeteilt. Der Player wählt einen Track auf der Grundlage der verfügbaren Netzwerkbandbreite aus.
Jeder Track ist in Abschnitte mit einer bestimmten Dauer unterteilt, in der Regel zwischen 2 und 10 Sekunden. So kann der Player schnell zwischen den Titeln wechseln, wenn sich die verfügbare Bandbreite ändert. Der Player ist für das Zusammenfügen dieser Abschnitte für eine nahtlose Wiedergabe verantwortlich.
Adaptive Titelauswahl
Das Herzstück des adaptiven Streaming ist die Auswahl des für die aktuelle Umgebung am besten geeigneten Titels. Aktualisieren Sie Ihre App, um adaptive Streaming-Medien abzuspielen, indem Sie die adaptive Titelauswahl verwenden.
- Aktualisieren Sie
initializePlayer
mit dem folgenden Code:
PlayerActivity.java
private void initializePlayer() { if (player == null) { DefaultTrackSelector trackSelector = new DefaultTrackSelector(this); trackSelector.setParameters( trackSelector.buildUponParameters().setMaxVideoSizeSd()); player = new SimpleExoPlayer.Builder(this) .setTrackSelector(trackSelector) .build(); } // Remove or comment out. // player = new SimpleExoPlayer.Builder(this).build(); }
Erstellen Sie zunächst ein DefaultTrackSelector
, das für die Auswahl der Titel im Medienelement verantwortlich ist. Sagen Sie dann Ihrem trackSelector
, dass er nur Titel mit Standardauflösung oder niedriger auswählen soll – eine gute Möglichkeit, um die Daten des Benutzers auf Kosten der Qualität zu sparen. Schließlich übergeben Sie Ihr trackSelector
an Ihren Builder, damit es beim Erstellen der SimpleExoPlayer
-Instanz verwendet wird.
Erstellen eines adaptiven MediaItem
DASH ist ein weit verbreitetes adaptives Streaming-Format. Um DASH-Inhalte zu streamen, müssen Sie wie zuvor ein MediaItem
erstellen. Diesmal müssen wir jedoch ein MediaItem.Builder
anstelle von fromUri
verwenden.
Das liegt daran, dass fromUri
die Dateierweiterung verwendet, um das zugrunde liegende Medienformat zu bestimmen, unser DASH-URI jedoch keine Dateierweiterung hat, so dass wir beim Erstellen des MediaItem
einen MIME-Typ von APPLICATION_MPD
angeben müssen.
- Aktualisieren Sie
initializePlayer
wie folgt:
PlayerActivity.java
private void initializePlayer() { // Replace this line MediaItem mediaItem = MediaItem.fromUri(getString(R.string.media_url_mp4)); // With this MediaItem mediaItem = new MediaItem.Builder() .setUri(getString(R.string.media_url_dash)) .setMimeType(MimeTypes.APPLICATION_MPD) .build(); // Also remove the following lines MediaItem secondMediaItem = MediaItem.fromUri(getString(R.string.media_url_mp3)); player.addMediaItem(secondMediaItem);}
- Starten Sie die App neu und sehen Sie adaptives Videostreaming mit DASH in Aktion. Es ist ziemlich einfach mit ExoPlayer!
Andere adaptive Streaming-Formate
HLS (MimeTypes.APPLICATION_M3U8
) und SmoothStreaming (MimeTypes.APPLICATION_SS
) sind andere häufig verwendete adaptive Streaming-Formate, die beide von ExoPlayer unterstützt werden. Weitere Informationen zum Erstellen anderer adaptiver Medienquellen finden Sie in der ExoPlayer-Demo-App.
In den vorherigen Schritten haben Sie gelernt, wie man progressive und adaptive Medienstreams streamt. ExoPlayer erledigt hinter den Kulissen eine Menge Arbeit für Sie, einschließlich der folgenden:
- Zuweisung von Speicher
- Herunterladen von Containerdateien
- Extrahieren von Metadaten aus dem Container
- Dekodieren von Daten
- Wiedergabe von Video, Audio und Text auf dem Bildschirm und den Lautsprechern
Gelegentlich ist es nützlich zu wissen, was ExoPlayer zur Laufzeit tut, um das Wiedergabeerlebnis für Ihre Benutzer zu verstehen und zu verbessern.
Zum Beispiel könnten Sie Änderungen des Wiedergabezustands in der Benutzeroberfläche durch folgende Maßnahmen widerspiegeln:
- Anzeigen eines Lade-Drehknopfs, wenn der Player in einen Pufferzustand übergeht
- Anzeigen eines Overlays mit „Watch Next“-Optionen, wenn der Track beendet ist
ExoPlayer bietet mehrere Listener-Schnittstellen, die Callbacks für nützliche Ereignisse bereitstellen. Sie verwenden einen Listener, um zu protokollieren, in welchem Zustand sich der Player befindet.
Hören Sie zu
- Deklarieren Sie ein privates Mitglied vom Typ
PlaybackStateListener
in derPlayerActivity
. - Erstellen Sie eine
TAG
Konstante, die Sie später zur Protokollierung verwenden.
PlayerActivity.java
private PlaybackStateListener playbackStateListener;private static final String TAG = PlayerActivity.class.getName();
- Instantiiere das
playbackStateListener
am Anfang vononCreate
(es wird noch nicht kompiliert, aber das wird in Kürze behoben).
PlayerActivity.java
@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_player); playbackStateListener = new PlaybackStateListener();
- Verwendet Quick Fix, um die innere Klasse
PlaybackStateListener
automatisch zu erstellen.
Screenshot: Quick Fix Menü zum Erstellen einer fehlenden Klasse
- Implementieren Sie die
Player.EventListener
Schnittstelle. Diese wird verwendet, um Sie über wichtige Player-Ereignisse zu informieren, einschließlich Fehler und Änderungen des Wiedergabezustands. - Überschreiben Sie
onPlaybackStateChanged
, indem Sie den folgenden Code hinzufügen:
PlayerActivity.java
private class PlaybackStateListener implements Player.EventListener { @Override public void onPlaybackStateChanged(int playbackState) { String stateString; switch (playbackState) { case ExoPlayer.STATE_IDLE: stateString = "ExoPlayer.STATE_IDLE -"; break; case ExoPlayer.STATE_BUFFERING: stateString = "ExoPlayer.STATE_BUFFERING -"; break; case ExoPlayer.STATE_READY: stateString = "ExoPlayer.STATE_READY -"; break; case ExoPlayer.STATE_ENDED: stateString = "ExoPlayer.STATE_ENDED -"; break; default: stateString = "UNKNOWN_STATE -"; break; } Log.d(TAG, "changed state to " + stateString); }}
onPlaybackStateChanged
wird aufgerufen, wenn sich der Wiedergabezustand ändert. Der neue Zustand wird durch den Parameter playbackState
angegeben.
Der Player kann sich in einem der folgenden vier Zustände befinden:
State |
Description |
|
Der Player wurde instanziiert, aber noch nicht vorbereitet. |
|
Der Player ist nicht in der Lage, von der aktuellen Position aus zu spielen, da nicht genügend Daten gepuffert wurden. |
|
Der Player ist in der Lage, sofort von der aktuellen Position aus zu spielen. Das bedeutet, dass der Player automatisch mit der Medienwiedergabe beginnt, wenn die Eigenschaft playWhenReady des Players |
|
Der Player hat die Medienwiedergabe beendet. |
Registrieren Sie Ihren Listener
Damit Ihre Rückrufe aufgerufen werden, müssen Sie Ihren playbackStateListener
beim Player registrieren. Tun Sie das in initializePlayer
.
- Registrieren Sie den Listener, bevor die Wiedergabe vorbereitet wird.
PlayerActivity.java
private void initializePlayer() { if (player == null) { player.addListener(playbackStateListener); player.prepare();}
Auch hier müssen Sie aufräumen, um baumelnde Referenzen vom Player zu vermeiden, die ein Speicherleck verursachen könnten.
- Entfernen Sie den Listener in
releasePlayer
:
PlayerActivity.java
private void releasePlayer() { if (player != null) { player.removeListener(playbackStateListener); player.release(); player = null; }}
- Öffnen Sie logcat und führen Sie die Anwendung aus.
- Verwenden Sie die UI-Steuerelemente, um die Wiedergabe zu suchen, anzuhalten und fortzusetzen. Sie sollten sehen, wie sich der Wiedergabestatus in den Protokollen ändert.
Gehen Sie tiefer
ExoPlayer bietet eine Reihe anderer Listener, die nützlich sind, um die Wiedergabeerfahrung des Benutzers zu verstehen. Es gibt Hörer für Audio und Video, sowie einen AnalyticsListener
, der die Rückrufe von allen Hörern enthält. Einige der wichtigsten Methoden sind die folgenden:
-
onRenderedFirstFrame
wird aufgerufen, wenn das erste Bild eines Videos gerendert wird. Damit können Sie berechnen, wie lange der Benutzer warten musste, um sinnvolle Inhalte auf dem Bildschirm zu sehen. -
onDroppedVideoFrames
wird aufgerufen, wenn Videoframes fallen gelassen wurden. Ausgelassene Frames deuten darauf hin, dass die Wiedergabe fehlerhaft ist und die Benutzererfahrung wahrscheinlich schlecht ist. -
onAudioUnderrun
wird aufgerufen, wenn es eine Audio-Unterschreitung gegeben hat. Unterschreitungen verursachen hörbare Störungen im Ton und sind auffälliger als ausgelassene Videobilder.
AnalyticsListener
kann mit addAnalyticsListener
zu player
hinzugefügt werden. Es gibt auch entsprechende Methoden für die Audio- und Video-Listener.
Denken Sie darüber nach, welche Ereignisse für Ihre App und Ihre Benutzer wichtig sind. Weitere Informationen finden Sie unter Listening for player events. Das war’s mit den Ereignis-Listenern!
Bislang haben Sie die PlayerControlView
von ExoPlayer verwendet, um dem Benutzer einen Wiedergabe-Controller anzuzeigen.
Screenshot: Standard-Wiedergabesteuerung
Was, wenn Sie die Funktionalität oder das Aussehen dieser Steuerelemente ändern möchten?
Die erste einfache Anpassung besteht darin, den Controller überhaupt nicht zu verwenden. Dies kann einfach durch die Verwendung des use_controller
-Attributs auf dem PlayerView
-Element innerhalb von activity_player.xml
erfolgen.
- Setzen Sie
use_controller
auffalse
und das Steuerelement wird nicht mehr angezeigt:
activity_player.xml
<com.google.android.exoplayer2.ui.PlayerView app:use_controller="false"/>
- Fügen Sie den folgenden Namespace zu Ihrem
FrameLayout
hinzu:
activity_player.xml
<FrameLayout xmlns:app="http://schemas.android.com/apk/res-auto">
Versuchen Sie es jetzt.
Anpassen des Verhaltens
PlayerControlView
hat mehrere Attribute, die sein Verhalten beeinflussen. Verwenden Sie show_timeout
, fastforward_increment
und rewind_increment
, um das Verhalten des Controllers anzupassen.
- Entfernen Sie
app:use_controller="false"
. - Ändern Sie die Playeransicht, um
show_timeout
,fastforward_increment
undrewind_increment
zu verwenden:
activity_player.xml
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" app:show_timeout="10000" app:fastforward_increment="30000" app:rewind_increment="30000"/>
- Der
show_timeout
-Wert teilt demPlayerView
die Verzögerung in Millisekunden mit, bevor das Steuerelement ausgeblendet wird, nachdem der Benutzer zuletzt damit interagiert hat. - Die Werte
fastforward_increment
undrewind_increment
teilen dem Player die Zeit in Millisekunden mit, um vor- oder zurückzuspringen, wenn der Benutzer auf die Schaltflächen für den schnellen Vorlauf oder den Rücklauf tippt.
Die Attribute des PlayerControlView
können auch programmatisch festgelegt werden.
Anpassen des Aussehens
Nun, das ist ein guter Anfang. Aber was ist, wenn man das PlayerControlView
anders aussehen lassen will oder ändern will, welche Schaltflächen angezeigt werden? Die Implementierung von PlayerControlView
geht nicht davon aus, dass irgendwelche Schaltflächen vorhanden sind, also ist es einfach, sie zu entfernen und neue hinzuzufügen.
Schauen Sie sich an, wie Sie PlayerControlView
anpassen können.
- Erstellen Sie eine neue Layout-Datei
custom_player_control_view.xml
im Ordnerplayer-lib/res/layout/
. - Wählen Sie aus dem Kontextmenü des Layout-Ordners Neu – Layout-Ressourcendatei und nennen Sie sie
custom_player_control_view.xml
.
Screenshot: Die Layout-Datei für die Player-Steuerungsansicht wurde erstellt.
- Kopieren Sie die ursprüngliche Layout-Datei von hier nach
custom_player_control_view.xml
. - Entfernen Sie die
ImageButton
-Elemente mit der ID@id/exo_prev
und@id/exo_next
.
Um Ihr benutzerdefiniertes Layout zu verwenden, müssen Sie das Attribut app:controller_layout_id
des PlayerView
-Elements in der activity_player.xml
-Datei setzen.
- Verwenden Sie die Layout-ID Ihrer benutzerdefinierten Datei wie im folgenden Codeschnipsel:
activity_player.xml
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent" app:controller_layout_id="@layout/custom_player_control_view"/>
- Starten Sie die App erneut. Die Player-Steuerungsansicht verfügt nicht mehr über die Schaltflächen Vorheriges und Nächstes.
Screenshot: Benutzerdefinierte Player-Steuerungsansicht ohne die Schaltflächen „Vorheriges“ und „Nächstes“
Sie können beliebige Änderungen in der Layout-Datei vornehmen. Standardmäßig werden die Farben des Android-Themas gewählt. Sie können dies überschreiben, um das Design Ihrer App anzupassen.
- Fügen Sie ein
android:tint
-Attribut zu jedemImageButton
-Element hinzu:
custom_player_control_view.xml
<ImageButton android:id="@id/exo_rew" android:tint="#FF00A6FF" style="@style/ExoMediaButton.Rewind"/>
- Ändern Sie alle
android:textColor
-Attribute, die Sie in Ihrer benutzerdefinierten Datei finden, in dieselbe Farbe:#FF00A6FF
.
custom_player_control_view.xml
<TextView android:id="@id/exo_position" android:textColor="#FF00A6FF"/><TextView android:id="@id/exo_duration" android:textColor="#FF00A6FF"/>
- Starten Sie die Anwendung. Jetzt haben Sie schöne, farbige UI-Komponenten!
Screenshot: Eingefärbte Schaltflächen und Textansicht
Den Standardstil außer Kraft setzen
Sie haben gerade eine benutzerdefinierte Layout-Datei erstellt und diese mit controller_layout_id
in activity_player.xml
referenziert.
Eine andere Möglichkeit ist, die Standard-Layout-Datei außer Kraft zu setzen, die PlayerControlView
verwendet. Der Quellcode von PlayerControlView
sagt uns, dass er R.layout.exo_player_control_view
für das Layout verwendet. Wenn Sie unsere eigene Layout-Datei mit demselben Dateinamen erstellen, verwendet PlayerControlView
stattdessen Ihre Datei.
- Entfernen Sie das Attribut
controller_layout_id
, das Sie gerade hinzugefügt haben. - Löschen Sie die Datei
custom_player_control_view.xml
.
Die PlayerView
in activity_player.xml
sollte nun wie folgt aussehen:
activity_player.xml
<com.google.android.exoplayer2.ui.PlayerView android:id="@+id/video_view" android:layout_width="match_parent" android:layout_height="match_parent"/>
- Erstelle eine Datei mit dem Namen
exo_player_control_view.xml
imres/layout
-Ordner deines Bibliotheksmodulsplayer-lib
. - Füge den folgenden Code in
exo_player_control_view.xml
ein, um eine Wiedergabetaste, eine Pausentaste und einImageView
mit einem Logo hinzu:
exo_player**_control_view.xml**
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="bottom" android:layoutDirection="ltr" android:background="#CC000000" android:orientation="vertical"> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:paddingTop="4dp" android:orientation="horizontal"> <ImageButton android:id="@id/exo_play" style="@style/ExoMediaButton.Play"/> <ImageButton android:id="@id/exo_pause" style="@style/ExoMediaButton.Pause"/> </LinearLayout> <ImageView android:contentDescription="@string/logo" android:src="@drawable/google_logo" android:layout_width="match_parent" android:layout_height="wrap_content"/></LinearLayout>
Dies zeigt, wie Sie hier Ihre eigenen Elemente hinzufügen und sie mit Standard-Steuerelementen mischen können. ExoPlayerView
verwendet nun Ihr benutzerdefiniertes Steuerelement und die gesamte Logik zum Ein- und Ausblenden bei der Interaktion mit dem Steuerelement bleibt erhalten.
Glückwunsch! Sie haben viel über die Integration von ExoPlayer in Ihre Anwendung gelernt.