Produktneuheiten
Verbesserte Medienwiedergabe: Einführung des Vorabladens mit Media3 – Teil 1
Lesezeit: 8 Minuten
In den heutigen mediacentrierten Apps ist eine reibungslose, unterbrechungsfreie Wiedergabe entscheidend für eine gute Nutzererfahrung. Nutzer erwarten, dass ihre Videos sofort und ohne Unterbrechungen abgespielt werden.
Die größte Herausforderung ist die Latenz. Normalerweise beginnt ein Videoplayer erst mit der Arbeit – Verbinden, Herunterladen, Parsen, Puffern –, nachdem der Nutzer ein Element zur Wiedergabe ausgewählt hat. Dieser reaktive Ansatz ist im Kontext von Kurzvideos heutzutage 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 Wesentliche beim Preloading.
Die wichtigsten Vorteile des Preloadings sind:
- 🚀 Schnellerer Start der Wiedergabe:Videos sind sofort verfügbar, was zu schnelleren Übergängen zwischen Elementen und einem sofortigen Start führt.
- 📉 Weniger Pufferung: Durch das proaktive Laden von Daten ist es viel unwahrscheinlicher, 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 Nutzer.
In dieser dreiteiligen Reihe stellen wir die leistungsstarken Media3-Dienstprogramme zum (Vor-)Laden von Komponenten vor und gehen genauer darauf ein.
- Im ersten Teil geht es um die Grundlagen: die verschiedenen in Media3 verfügbaren Vorabladestrategien, das Aktivieren von „PreloadConfiguration“ und das Einrichten von „DefaultPreloadManager“, damit deine App Elemente vorab laden kann. Am Ende dieses Blogs sollten Sie in der Lage sein, Media-Elemente mit Ihrem konfigurierten Ranking und Ihrer konfigurierten Dauer vorzuladen und abzuspielen.
- In Teil 2 werden wir uns mit fortgeschritteneren Themen von DefaultPreloadManager befassen: Verwendung von Listenern für Analysen, Best Practices für die Produktion wie das Sliding-Window-Muster und benutzerdefinierte freigegebene Komponenten von DefaultPreloadManager und ExoPlayer.
- In Teil 3 sehen wir uns das Festplatten-Caching mit DefaultPreloadManager genauer an.
Vorabladen kann helfen. 🦸♀️
Die Idee hinter dem Preloading 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 können sofort wiedergegeben werden.
Stellen Sie sich das wie ein Restaurant vor. In einer geschäftigen Küche wird nicht auf eine Bestellung gewartet, bevor mit dem Zerkleinern von Zwiebeln begonnen wird. 🧅 Sie bereiten sich im Voraus vor. Das Vorladen ist die Vorbereitung für deinen Videoplayer.
Wenn die Funktion aktiviert ist, kann das Vorladen dazu beitragen, die Latenz beim Starten der Wiedergabe zu 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 den Player eingereiht. Die gepufferten Samples sind sofort verfügbar und können zum Rendern an den Codec gesendet werden.
In Media3 gibt es zwei primäre APIs für das Vorabladen, die jeweils für unterschiedliche Anwendungsfälle geeignet sind. Der erste Schritt ist die Auswahl der richtigen API.
1. Playlist-Elemente mit PreloadConfiguration vorab laden
Das ist der einfache Ansatz, der für lineare, sequenzielle Medien wie Playlists nützlich ist, bei denen die Wiedergabereihenfolge vorhersehbar ist (z. B. bei einer Reihe von Folgen). Sie geben dem Player die vollständige Liste der Media-Elemente über die Playlist-APIs von ExoPlayer und legen die PreloadConfiguration für den Player fest. Die nächsten Elemente in der Sequenz werden dann automatisch wie konfiguriert vorab geladen. Diese API versucht, die Wartezeit beim Beitreten zu optimieren, wenn ein Nutzer zum nächsten Element springt, bevor sich der Wiedergabepuffer bereits mit dem nächsten Element überschneidet.
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 Bandbreite konkurriert.
Wenn Sie sich noch nicht sicher sind, ob Sie das Preloading benötigen, ist diese API eine gute Option, um es auszuprobieren.
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)
Mit der oben gezeigten PreloadConfiguration versucht der Player, fünf Sekunden der Medien für das nächste Element in der Playlist vorzuladen.
Nachdem du die Funktion aktiviert hast, kannst du sie wieder deaktivieren, indem du PreloadConfiguration.DEFAULT verwendest:
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 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 und priorisiert sie basierend auf der Nähe zum aktuellen Standort des Nutzers. Außerdem bietet sie eine detaillierte Steuerung der vorzuladenden Inhalte, was sich für komplexe Szenarien wie dynamische Feeds mit Kurzvideos eignet.
PreloadManager einrichten
DefaultPreloadManager ist die kanonische Implementierung für PreloadManager.
Der Builder von DefaultPreloadManager kann sowohl den DefaultPreloadManager als auch alle ExoPlayer-Instanzen erstellen, die die vorab geladenen Inhalte abspielen. Wenn Sie einen DefaultPreloadManager erstellen möchten, müssen Sie ein TargetPreloadStatusControl übergeben, das der Preload-Manager abfragen kann, um herauszufinden, wie viel für ein Element geladen werden soll. Im folgenden Abschnitt wird ein Beispiel für TargetPreloadStatusControl erläutert und definiert.
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 gemeinsam genutzt werden.
Das ist auch schon alles! Sie haben jetzt einen Manager, der bereit ist, Anweisungen entgegenzunehmen.
Dauer und Ranking mit TargetPreloadStatusControl konfigurieren
Was ist, wenn Sie beispielsweise 10 Sekunden Video vorab laden möchten? Sie können die Position Ihrer Media-Elemente im Karussell angeben. Der DefaultPreloadManager priorisiert das Laden der Elemente basierend darauf, wie nah sie an dem Element sind, das der Nutzer gerade abspielt.
Wenn Sie steuern möchten, wie viel Zeit des Elements vorab geladen werden soll, können Sie das mit DefaultPreloadManager.PreloadStatus festlegen.
Beispiel:
- Element A hat die höchste Priorität. Lade 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. Es werden nur Tracks geladen.
- Artikel D hat eine noch geringere Priorität. Bereiten Sie sich einfach vor.
- Alle anderen Elemente sind weit entfernt. Es soll nichts vorab geladen werden.
Diese detaillierte Steuerung kann Ihnen helfen, die Ressourcennutzung zu optimieren, was für eine nahtlose 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
}
}
Hinweis: Mit PreloadManager können sowohl die vorherigen als auch die nächsten Elemente vorab geladen werden. Bei PreloadConfiguration werden nur die nächsten Elemente berücksichtigt.
Vorab geladene Elemente verwalten
Nachdem Sie Ihren Manager erstellt haben, können Sie ihm mitteilen, woran er arbeiten soll. Wenn der Nutzer durch einen Feed scrollt, identifizieren Sie die anstehenden Videos und fügen sie dem Manager hinzu. Die Interaktion mit dem PreloadManager ist eine zustandsbasierte Konversation zwischen Ihrer Benutzeroberfläche und der Preloading-Engine.
1. Medienelemente hinzufügen
Wenn Sie Ihren Feed mit Daten füllen, müssen Sie den Manager über die zu erfassenden Media informieren. Wenn Sie gerade erst anfangen, können Sie die gesamte Liste hinzufügen, die Sie vorab laden möchten. Anschließend können Sie der Liste nach Bedarf einzelne Elemente hinzufügen. Sie haben die volle Kontrolle darüber, welche Elemente in der Vorabladeliste enthalten sind. Das bedeutet, dass Sie auch 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 soll der Manager die neue Liste neu bewerten. Das kann durch einen Hinweis erfolgen, dass sich etwas geändert hat, z. B. durch das Hinzufügen oder Entfernen eines Elements oder durch den Wechsel des Nutzers zu einem neuen Element.
preloadManager.invalidate()
2. Artikel abrufen und abspielen
Hier kommt die Hauptwiedergabelogik. Wenn der Nutzer das Video abspielen möchte, müssen Sie keine neue MediaSource erstellen. Stattdessen fragen Sie den PreloadManager nach dem, was er bereits vorbereitet hat. Sie können die MediaSource über den Preload Manager mit dem MediaItem 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. In diesem Fall können Sie das MediaItem 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()
Wenn Sie die vom PreloadManager abgerufene MediaSource vorbereiten, können Sie nahtlos vom Preloading zur Wiedergabe übergehen und dabei die Daten verwenden, die sich bereits im Arbeitsspeicher befinden. 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 den aktuellen Wiedergabeindex zu informieren, damit er immer Elemente in der Nähe des aktuellen Index für das Vorabladen priorisieren kann.
preloadManager.setCurrentPlayingIndex(currentIndex) // Need to call invalidate() to update the priorities preloadManager.invalidate()
4. Element entfernen
Damit der Tracker effizient bleibt, sollten Sie Elemente entfernen, die nicht mehr verfolgt werden müssen, z. B. Elemente, die sich weit entfernt vom aktuellen Standort des Nutzers befinden.
// 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. Dies empfiehlt sich an der Stelle, an der Sie die Ressourcen des Players bereits freigeben. Es wird empfohlen, den Manager vor dem Player freizugeben, da der Player weiter abgespielt werden kann, wenn kein weiteres Preloading erforderlich ist.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
Demo zeigen
Sehen Sie sich die Funktion in Aktion an. 👍
In der Demo unten sehen Sie rechts die Auswirkungen von PreloadManager mit schnelleren Ladezeiten. Links ist die aktuelle Situation dargestellt. Sie können sich auch den Beispielcode für die Demo ansehen. Bonus: Die Startlatenz wird auch für jedes Video angezeigt.
Wie geht es weiter?
Das war Teil 1. Sie haben jetzt die Tools, um ein dynamisches Preloading-System zu erstellen. Sie können entweder PreloadConfiguration verwenden, um das nächste Element einer Playlist in ExoPlayer vorab zu laden, oder DefaultPreloadManager einrichten, Elemente spontan hinzufügen und entfernen, den Zielstatus für das Vorabladen konfigurieren und die vorab geladenen Inhalte für die Wiedergabe richtig abrufen.
In Teil 2 gehen wir genauer auf DefaultPreloadManager ein. Wir sehen uns an, wie du auf Preloading-Ereignisse reagieren kannst, besprechen Best Practices wie die Verwendung eines gleitenden Fensters, um Speicherprobleme zu vermeiden, und werfen einen Blick auf benutzerdefinierte freigegebene Komponenten von ExoPlayer und DefaultPreloadManager.
Möchten Sie uns Feedback geben? Wir freuen uns auf Ihre Nachricht.
Bleiben Sie dran und sorgen Sie dafür, dass Ihre App schneller wird. 🚀
Weiterlesen
-
Produktneuheiten
Willkommen zum zweiten Teil unserer dreiteiligen Serie zum Vorabladen von Media mit Media3. In dieser Reihe erfahren Sie, wie Sie in Ihren Android-Apps Medienanwendungen mit hoher Reaktionsfähigkeit und geringer Latenz entwickeln.
Mayuri Khinvasara Khabya • Lesezeit: 9 Minuten
-
Produktneuheiten
Android Studio Panda 4 ist jetzt stabil und kann für die Produktion verwendet werden. Diese Version bietet den Planungsmodus, die Vorhersage des nächsten Bearbeitungsschritts und weitere Funktionen, die das Erstellen hochwertiger Android-Apps noch einfacher machen.
Matt Dyor • Lesezeit: 5 Minuten
-
Produktneuheiten
Wenn Sie Android-Entwickler sind und innovative KI-Funktionen in Ihre App einbinden möchten, haben wir vor Kurzem leistungsstarke neue Updates eingeführt.
Thomas Ezan • Lesezeit: 3 Minuten
Auf dem Laufenden bleiben
Lassen Sie sich Woche für Woche die neuesten Informationen zur Android-Entwicklung zusenden.