Produktneuheiten
Optimierte Medienwiedergabe: Einführung in das Vorabladen mit Media3 – Teil 1
Lesezeit: 8 Minuten
In den heutigen medienzentrierten Apps ist eine reibungslose, unterbrechungsfreie Wiedergabe entscheidend für eine gute Nutzererfahrung. Nutzer erwarten, dass Videos sofort starten und ohne Pausen abgespielt werden.
Die größte Herausforderung ist die Latenz. Traditionell beginnt ein Videoplayer erst mit seiner Arbeit – Verbindung herstellen, herunterladen, parsen, puffern –, nachdem der Nutzer ein Element zur Wiedergabe ausgewählt hat. Dieser reaktive Ansatz ist für die heutigen Kurzvideos zu langsam. Die Lösung besteht darin, proaktiv zu sein. Wir müssen vorhersagen, was sich der Nutzer als Nächstes ansehen wird, und die Inhalte rechtzeitig vorbereiten. Das ist das Wesen des Vorabladens.
Die wichtigsten Vorteile des Vorabladens:
- 🚀 Schnellere Wiedergabe: Videos sind bereits fertig, was zu schnelleren Übergängen zwischen Elementen und einem sofortigen Start führt.
- 📉 Weniger Pufferung: Durch das proaktive Laden von Daten ist es viel weniger wahrscheinlich, dass die Wiedergabe unterbrochen wird, z. B. aufgrund von Netzwerkproblemen.
- ✨ Reibungslosere Nutzererfahrung: Die Kombination aus schnelleren Starts und weniger Pufferung sorgt für eine flüssigere, nahtlose Interaktion für die Nutzer.
In dieser dreiteiligen Reihe stellen wir die leistungsstarken Dienstprogramme von Media3 zum (Vorab-)Laden von Komponenten vor und gehen näher darauf ein.
- Im ersten Teil behandeln wir die Grundlagen: die verschiedenen Vorabladestrategien in Media3, das Aktivieren von PreloadConfiguration und das Einrichten von DefaultPreloadManager, damit Ihre App Elemente vorab laden kann. Am Ende dieses Blogposts sollten Sie in der Lage sein, Mediendateien mit der konfigurierten Rangfolge und Dauer vorab zu laden und abzuspielen.
- Im zweiten Teil gehen wir auf fortgeschrittenere Themen von DefaultPreloadManager ein: Listener für Analysen verwenden und Best Practices für die Produktion wie das Sliding-Window-Muster und benutzerdefinierte freigegebene Komponenten von DefaultPreloadManager und ExoPlayer kennenlernen.
- Im dritten Teil gehen wir näher auf das Festplatten-Caching mit DefaultPreloadManager ein.
Vorabladen als Lösung 🦸♀️
Die Grundidee hinter dem Vorabladen ist einfach: Laden Sie Medieninhalte, bevor Sie sie benötigen. Wenn ein Nutzer zum nächsten Video wischt, sind die ersten Segmente des Videos bereits heruntergeladen und verfügbar und können sofort abgespielt werden.
Stellen Sie sich das wie in einem Restaurant vor. In einer geschäftigen Küche wird nicht auf eine Bestellung gewartet, um mit dem Zerkleinern von Zwiebeln zu beginnen. 🧅 Die Vorbereitungen werden im Voraus erledigt. Das Vorabladen ist die Vorbereitung für Ihren Videoplayer.
Wenn das Vorabladen aktiviert ist, kann es die Latenz beim Wechsel zu einem anderen Element minimieren, wenn ein Nutzer zum nächsten Element springt, bevor der Wiedergabepuffer das nächste Element erreicht. Der erste Zeitraum des nächsten Fensters wird vorbereitet und Video-, Audio- und Textbeispiele werden gepuffert. Der vorab geladene Zeitraum wird später in die Warteschlange des Players gestellt. Die gepufferten Beispiele sind sofort verfügbar und können dem Codec zur Wiedergabe zugeführt werden.
In Media3 gibt es zwei primäre APIs für das Vorabladen, die jeweils für unterschiedliche Anwendungsfälle geeignet sind. Die richtige API auszuwählen ist der erste Schritt.
1. Playlist-Elemente mit PreloadConfiguration vorab laden
Dies ist der einfache Ansatz, der für lineare, sequenzielle Medien wie Playlists nützlich ist, bei denen die Wiedergabereihenfolge vorhersehbar ist (z. B. eine Reihe von Folgen). Sie geben dem Player die vollständige Liste der Mediendateien mit den Playlist-APIs von ExoPlayer und legen die PreloadConfiguration für den Player fest. Dann werden die nächsten Elemente in der Sequenz automatisch wie konfiguriert vorab geladen. Diese API versucht, die Latenz beim Wechsel zu einem anderen Element zu optimieren, wenn ein Nutzer zum nächsten Element springt, bevor der Wiedergabepuffer das nächste Element erreicht.
Das Vorabladen wird nur gestartet, wenn keine Medien für die laufende Wiedergabe geladen werden. So wird verhindert, dass es mit der primären Wiedergabe um die Bandbreite konkurriert.
Wenn Sie sich noch nicht sicher sind, ob Sie das Vorabladen benötigen, ist diese API eine gute Option, um es auszuprobieren.
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)Mit der oben genannten PreloadConfiguration versucht der Player, fünf Sekunden Medien für das nächste Element in der Playlist vorab zu laden.
Nach der Aktivierung kann das Vorabladen von Playlists wieder deaktiviert werden. Verwenden Sie dazu PreloadConfiguration.DEFAULT:
player.preloadConfiguration = PreloadConfiguration.DEFAULT
2. Dynamische Listen mit PreloadManager vorab laden
Für dynamische Benutzeroberflächen wie vertikale Feeds oder Karussells, bei denen das nächste Element durch die Nutzerinteraktion bestimmt wird, ist die PreloadManager API geeignet. Dies ist eine neue leistungsstarke, eigenständige Komponente in der Media3 ExoPlayer-Bibliothek, die speziell für das proaktive Vorabladen entwickelt wurde. Sie verwaltet eine Sammlung potenzieller MediaSources, priorisiert sie basierend auf der Nähe zur aktuellen Position des Nutzers und bietet eine detaillierte Steuerung darüber, was vorab geladen werden soll. Sie eignet sich für komplexe Szenarien wie dynamische Feeds mit Kurzvideos.
PreloadManager einrichten
Der DefaultPreloadManager ist die kanonische Implementierung für PreloadManager.
Mit dem Builder von DefaultPreloadManager können sowohl der DefaultPreloadManager als auch alle ExoPlayer-Instanzen erstellt werden, die die vorab geladenen Inhalte abspielen. Um einen DefaultPreloadManager zu erstellen, müssen Sie ein TargetPreloadStatusControl übergeben, das der Vorablademanager abfragen kann, um zu ermitteln, wie viel für ein Element geladen werden soll. Wir erklären und definieren ein Beispiel für TargetPreloadStatusControl im folgenden Abschnitt.
val preloadManagerBuilder = DefaultPreloadManager.Builder(context, targetPreloadStatusControl) val preloadManager = val preloadManagerBuilder.build() // Build ExoPlayer with DefaultPreloadManager.Builder val player = preloadManagerBuilder.buildExoPlayer()
Es ist erforderlich, denselben Builder für ExoPlayer und DefaultPreloadManager zu verwenden, damit die Komponenten unter der Haube korrekt freigegeben werden.
Geschafft! Sie haben jetzt einen Manager, der Anweisungen entgegennehmen kann.
Dauer und Rangfolge mit TargetPreloadStatusControl konfigurieren
Was ist, wenn Sie beispielsweise 10 Sekunden Video vorab laden möchten? Sie können die Position Ihrer Mediendateien im Karussell angeben. Der DefaultPreloadManager priorisiert das Laden der Elemente danach, wie nah sie an dem Element sind, das der Nutzer gerade abspielt.
Wenn Sie steuern möchten, wie viel von der Dauer des Elements vorab geladen werden soll, können Sie das mit DefaultPreloadManager.PreloadStatus angeben.
Beispiel:
- Element „A“ hat die höchste Priorität. Laden Sie 5 Sekunden Video.
- Element „B“ hat eine mittlere Priorität. Wenn Sie es erreichen, laden Sie 3 Sekunden Video.
- Element „C“ hat eine geringere Priorität. Laden Sie nur Tracks.
- Element „D“ hat eine noch geringere Priorität. Bereiten Sie es einfach vor.
- Alle anderen Elemente sind weit entfernt. Laden Sie nichts vorab.
Mit dieser detaillierten Steuerung können Sie die Ressourcennutzung optimieren, was für eine reibungslose Wiedergabe empfohlen wird.
import androidx.media3.exoplayer.DefaultPreloadManager.PreloadStatus
class MyTargetPreloadStatusControl(
currentPlayingIndex: Int = C.INDEX_UNSET
) : TargetPreloadStatusControl<Int,PreloadStatus> {
// The app is responsible for updating this based on UI state
override fun getTargetPreloadStatus(index: Int): PreloadStatus? {
val distance = index - currentPlayingIndex
// Adjacent items (Next): preload 5 seconds
if (distance == 1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED and suggest loading // 5000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(5000L)
}
// Adjacent items (Previous): preload 3 seconds
else if (distance == -1) {
// Return a PreloadStatus that is labelled by STAGE_SPECIFIED_RANGE_LOADED //and suggest loading 3000ms from the default start position
return PreloadStatus.specifiedRangeLoaded(3000L)
}
// Items two positions away: just select tracks
else if (distance) == 2) {
// Return a PreloadStatus that is labelled by STAGE_TRACKS_SELECTED
return PreloadStatus.TRACKS_SELECTED
}
// Items four positions away: just select prepare
else if (abs(distance) <= 4) {
// Return a PreloadStatus that is labelled by STAGE_SOURCE_PREPARED
return PreloadStatus.SOURCE_PREPARED
}
// All other items are too far away
return null
}
}Tipp: PreloadManager kann sowohl die vorherigen als auch die nächsten Elemente vorab laden, während PreloadConfiguration nur die nächsten Elemente berücksichtigt.
Vorabladen von Elementen verwalten
Nachdem Sie Ihren Manager erstellt haben, können Sie ihm mitteilen, was er tun soll. Wenn Ihr Nutzer durch einen Feed scrollt, identifizieren Sie die kommenden Videos und fügen sie dem Manager hinzu. Die Interaktion mit dem PreloadManager ist eine zustandsgesteuerte Konversation zwischen Ihrer Benutzeroberfläche und der Vorablademaschine.
1. Mediendateien hinzufügen
Wenn Sie Ihren Feed füllen, müssen Sie den Manager über die Medien informieren, die er verfolgen muss. Wenn Sie gerade erst anfangen, können Sie die gesamte Liste hinzufügen, die Sie vorab laden möchten. Anschließend können Sie bei Bedarf einzelne Elemente zur Liste hinzufügen. Sie haben die volle Kontrolle darüber, welche Elemente in der Vorabladeliste enthalten sind. Das bedeutet auch, dass Sie verwalten müssen, was dem Manager hinzugefügt und daraus entfernt wird.
val initialMediaItems = pullMediaItemsFromService(/* count= */ 20)
for (index in 0 until initialMediaItems.size) {
preloadManager.add(
initialMediaItems.get(index),index)
)
}Der Manager beginnt nun im Hintergrund mit dem Abrufen von Daten für dieses MediaItem.
Nach dem Hinzufügen müssen Sie den Manager auffordern, die neue Liste neu zu bewerten. Das deutet darauf hin, dass sich etwas geändert hat, z. B. durch das Hinzufügen oder Entfernen eines Elements oder wenn der Nutzer ein neues Element abspielt.
preloadManager.invalidate()
2. Element abrufen und abspielen
Hier kommt die Hauptwiedergabelogik. Wenn der Nutzer dieses Video abspielen möchte, müssen Sie keine neue MediaSource erstellen. Stattdessen fordern Sie die PreloadManager für die bereits vorbereitete an. Sie können die MediaSource mit dem MediaItem aus dem PreloadManager abrufen.
Wenn das abgerufene Element aus dem PreloadManager null ist, bedeutet das, dass das MediaItem noch nicht vorab geladen oder dem PreloadManager hinzugefügt wurde. Sie können das MediaItem also direkt festlegen.
// When a media item is about to display on the screen
val mediaSource = preloadManager.getMediaSource(mediaItem)
if (mediaSource!= null) {
player.setMediaSource(mediaSource)
} else {
// If mediaSource is null, that mediaItem hasn't been added yet.
// So, send it directly to the player.
player.setMediaItem(mediaItem)
}
player.prepare()
// When the media item is displaying at the center of the screen
player.play()Indem Sie die aus dem PreloadManager abgerufene MediaSource vorbereiten, können Sie nahtlos vom Vorabladen zur Wiedergabe übergehen und die bereits im Arbeitsspeicher vorhandenen Daten verwenden. Dadurch wird die Startzeit verkürzt.
3. Aktuellen Index mit der Benutzeroberfläche synchronisieren
Da unser Feed bzw. unsere Liste dynamisch sein kann, ist es wichtig, den PreloadManager über Ihren aktuellen Wiedergabeindex zu informieren, damit er immer Elemente priorisieren kann, die sich in der Nähe Ihres aktuellen Index befinden.
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
4. Element entfernen
Damit der Manager effizient bleibt, sollten Sie Elemente entfernen, die er nicht mehr verfolgen muss, z. B. Elemente, die weit von der aktuellen Position des Nutzers entfernt sind.
// When an item is too far from the current playing index preloadManager.remove(mediaItem)
Wenn Sie alle Elemente auf einmal löschen möchten, können Sie preloadManager.reset() aufrufen.
5. Manager freigeben
Wenn Sie den PreloadManager nicht mehr benötigen (z.B. wenn Ihre Benutzeroberfläche zerstört wird), müssen Sie ihn freigeben, um seine Ressourcen freizugeben. Ein guter Ort dafür ist der, an dem Sie bereits die Ressourcen Ihres Players freigeben. Es wird empfohlen, den Manager vor dem Player freizugeben, da der Player weiter abspielen kann, wenn Sie kein Vorabladen mehr benötigen.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
Demo zeigen
Live in Aktion ansehen 👍
In der Demo unten sehen Sie rechts die Auswirkungen von PreloadManager, der schnellere Ladezeiten bietet. Links sehen Sie die bestehende Erfahrung. Sie können sich auch das Code beispiel für die Demo ansehen. (Bonus: Außerdem wird die Startlatenz für jedes Video angezeigt)
Wie geht es weiter?
Das war Teil 1. Sie haben jetzt die Tools, um ein dynamisches Vorabladensystem zu erstellen. Sie können entweder PreloadConfiguration verwenden, um das nächste Element einer Playlist in ExoPlayer vorab zu laden, oder einen DefaultPreloadManager einrichten, Elemente im laufenden Betrieb hinzufügen und entfernen, den Zielstatus für das Vorabladen konfigurieren und die vorab geladenen Inhalte korrekt zur Wiedergabe abrufen.
Im zweiten Teil gehen wir näher auf den DefaultPreloadManager ein. Wir sehen uns an, wie Sie auf Vorabladen-Ereignisse warten, besprechen Best Practices wie die Verwendung eines Sliding Window, um Speicherprobleme zu vermeiden, und werfen einen Blick auf benutzerdefinierte freigegebene Komponenten von ExoPlayer und DefaultPreloadManager.
Haben Sie Feedback für uns, das Sie teilen möchten? Wir freuen uns auf Ihre Meinung.
Bleiben Sie dran und machen Sie Ihre App schneller! 🚀
Weiterlesen
-
Produktneuheiten
Willkommen zum zweiten Teil unserer dreiteiligen Reihe zum Vorabladen von Medien mit Media3. In dieser Reihe erfahren Sie, wie Sie in Ihren Android-Apps hochreaktive Medien mit geringer Latenz erstellen.
Mayuri Khinvasara Khabya • Lesezeit: 9 Minuten
-
Produktneuheiten
Von Augmented-Reality-Overlays bis hin zu vollständig immersiven Umgebungen: Das Android XR-Ökosystem wächst rasant. Das Samsung Galaxy XR ist bereits verfügbar.
Stevan Silva, Vinny DaSilva • Lesezeit: 3 Minuten
-
Produktneuheiten
Jedes Jahr gibt es auf der Google I/O neue Ankündigungen und Ressourcen für verschiedene Ökosysteme und Produkte, einschließlich der Android-Entwicklung. Da sich die Entwicklung hin zu KI- und agentengestützten Tools verlagert, haben wir unser Angebot erweitert, um Sie besser zu unterstützen, unabhängig davon, wie Sie für Android entwickeln.
Simona Milanovic • Lesezeit: 2 Minuten
Auf dem Laufenden bleiben
Lassen Sie sich Woche für Woche die neuesten Informationen zur Android-Entwicklung zusenden.