Media-Streaming mit ExoPlayer

4ec261ee5a0bd0cc.png

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

  • Moderate Kenntnisse der Android-Entwicklung und von Android Studio

Was Sie tun werden

  • Erstellen Sie eine SimpleExoPlayerInstanz, 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 MediaItems, 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

  1. Starten Sie Android Studio.
  2. Wählen Sie Datei > Neu > Projekt importieren*.*
  3. Importieren Sie das Ausgangsprojekt aus exoplayer-codelab-00.

f2e5feb9ade6c7f7.png

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.

  1. 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.

21c0dae6245fbd31.png

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.

  1. Öffnen Sie die build.gradle-Datei des player-lib-Moduls.
  2. 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

  1. Öffnen Sie die Layout-Ressourcendatei activity_player.xml aus dem Modul player-lib.
  2. Positionieren Sie den Cursor innerhalb des Elements FrameLayout.
  3. Starten Sie die Eingabe von <PlayerView und lassen Sie Android Studio das Element PlayerView automatisch vervollständigen.
  4. Verwenden Sie match_parent für width und height.
  5. 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.

  1. In der PlayerActivity müssen Sie nun die Videoansicht finden, damit Sie sie in der onCreate-Methode der Aktivität richtig einrichten können.

PlayerActivity.java

@Overrideprotected void onCreate(Bundle savedInstanceState) { playerView = findViewById(R.id.video_view);}
  1. Fügen Sie das playerView-Memberfeld zu Ihrer PlayerActivity-Klasse hinzu. Stellen Sie sicher, dass der Typ der Ansicht PlayerView 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

b0f7f70115bb90e5.png

Screenshot: Quick-Fix-Menü zum Erstellen eines Mitgliedsfeldes

Erstellen eines ExoPlayers

Um Streaming-Medien abzuspielen, benötigen Sie ein ExoPlayerObjekt. 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.

  1. 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.

  1. Klicken Sie bei geöffnetem PlayerActivity auf das Menü „Code“ > Überschreiben Sie Methoden….
  2. Wählen Sie onStart, onResume, onPause und onStop.
  3. Initialisieren Sie den Player im onStart– oder onResume-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.

  1. 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.

  1. Freigeben Sie Ressourcen mit releasePlayer (das Sie kurz erstellen) in onPause und onStop.

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 releasePlayerMethode erstellen, die die Ressourcen des Players freigibt und ihn zerstört.

  1. 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.

  1. 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. Da playWhenReady anfänglich true 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. Sowohl currentWindow als auch playbackPosition 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.

1d049aead0483777.png

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.

  1. Starten Sie eine andere App und bringen Sie Ihre App wieder in den Vordergrund. Wird sie an der richtigen Stelle fortgesetzt?
  2. 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?
  3. 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.

  1. Ändern Sie die URI in der initializePlayer auf R.string.media_url_mp4.
  2. 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.

4ebd0b0f98593691.png

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 MediaItems 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.

  1. 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 1f79fee4d082870f.pngund 39627002c03ce320.png verwenden, um in der Reihenfolge der Medienelemente zu navigieren.

7b5c034dafabe1bd.png

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.

  1. 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.

  1. 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);}
  1. 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

  1. Deklarieren Sie ein privates Mitglied vom Typ PlaybackStateListener in der PlayerActivity.
  2. Erstellen Sie eine TAGKonstante, die Sie später zur Protokollierung verwenden.

PlayerActivity.java

private PlaybackStateListener playbackStateListener;private static final String TAG = PlayerActivity.class.getName();
  1. Instantiiere das playbackStateListener am Anfang von onCreate (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();
  1. Verwendet Quick Fix, um die innere Klasse PlaybackStateListener automatisch zu erstellen.

b59ce69a22595ba7.png

Screenshot: Quick Fix Menü zum Erstellen einer fehlenden Klasse

  1. Implementieren Sie die Player.EventListenerSchnittstelle. Diese wird verwendet, um Sie über wichtige Player-Ereignisse zu informieren, einschließlich Fehler und Änderungen des Wiedergabezustands.
  2. Ü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

ExoPlayer.STATE_IDLE

Der Player wurde instanziiert, aber noch nicht vorbereitet.

ExoPlayer.STATE_BUFFERING

Der Player ist nicht in der Lage, von der aktuellen Position aus zu spielen, da nicht genügend Daten gepuffert wurden.

ExoPlayer.STATE_READY

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 true lautet. Wenn sie false ist, wird der Player angehalten.

ExoPlayer.STATE_ENDED

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.

  1. 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.

  1. Entfernen Sie den Listener in releasePlayer:

PlayerActivity.java

private void releasePlayer() { if (player != null) { player.removeListener(playbackStateListener); player.release(); player = null; }}

  1. Öffnen Sie logcat und führen Sie die Anwendung aus.
  2. 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.

bcfe17eebcad9e13.png

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.

  1. Setzen Sie use_controller auf false und das Steuerelement wird nicht mehr angezeigt:

activity_player.xml

<com.google.android.exoplayer2.ui.PlayerView app:use_controller="false"/>
  1. 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.

  1. Entfernen Sie app:use_controller="false".
  2. Ändern Sie die Playeransicht, um show_timeout, fastforward_increment und rewind_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 dem PlayerView die Verzögerung in Millisekunden mit, bevor das Steuerelement ausgeblendet wird, nachdem der Benutzer zuletzt damit interagiert hat.
  • Die Werte fastforward_increment und rewind_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.

  1. Erstellen Sie eine neue Layout-Datei custom_player_control_view.xml im Ordner player-lib/res/layout/.
  2. Wählen Sie aus dem Kontextmenü des Layout-Ordners Neu – Layout-Ressourcendatei und nennen Sie sie custom_player_control_view.xml.

ae1e3795726d4e4e.png

Screenshot: Die Layout-Datei für die Player-Steuerungsansicht wurde erstellt.

  1. Kopieren Sie die ursprüngliche Layout-Datei von hier nach custom_player_control_view.xml.
  2. 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.

  1. 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"/>
  1. Starten Sie die App erneut. Die Player-Steuerungsansicht verfügt nicht mehr über die Schaltflächen Vorheriges und Nächstes.

89e6535a22c8e321.png

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.

  1. Fügen Sie ein android:tint-Attribut zu jedem ImageButton-Element hinzu:

custom_player_control_view.xml

<ImageButton android:id="@id/exo_rew" android:tint="#FF00A6FF" style="@style/ExoMediaButton.Rewind"/>
  1. Ä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"/>
  1. Starten Sie die Anwendung. Jetzt haben Sie schöne, farbige UI-Komponenten!

e9835d65d6dd0634.png

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.

  1. Entfernen Sie das Attribut controller_layout_id, das Sie gerade hinzugefügt haben.
  2. 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"/>
  1. Erstelle eine Datei mit dem Namen exo_player_control_view.xml im res/layout-Ordner deines Bibliotheksmoduls player-lib.
  2. Füge den folgenden Code in exo_player_control_view.xml ein, um eine Wiedergabetaste, eine Pausentaste und ein ImageView 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.

Mehr erfahren

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht.