In den heutigen medienorientierten Apps ist eine reibungslose, unterbrechungsfreie Wiedergabe entscheidend für eine gute Nutzererfahrung. Nutzer erwarten, dass Videos sofort starten und ohne Unterbrechungen wiedergegeben werden.
Die größte Herausforderung ist die Latenz. Normalerweise beginnt ein Videoplayer erst dann mit der Arbeit (Verbindung herstellen, Herunterladen, Parsen, Zwischenspeichern), wenn der Nutzer ein Element für die Wiedergabe ausgewählt hat. Dieser reaktive Ansatz ist für den heutigen Kontext von Kurzvideos zu langsam. Die Lösung besteht darin, proaktiv zu sein. Wir müssen vorhersehen, was sich der Nutzer als Nächstes ansieht, und die Inhalte im Voraus bereitstellen. Das ist der Kern des Vorabladens.
Die wichtigsten Vorteile des Vorabladens sind:
- 🚀 Schnellerer Wiedergabestart:Videos sind bereits geladen, sodass die Übergänge zwischen den Elementen schneller sind und die Wiedergabe sofort beginnt.
- 📉 Weniger Zwischenspeichern:Durch das proaktive Laden von Daten ist es weitaus unwahrscheinlicher, dass die Wiedergabe ins Stocken gerät, z. B. aufgrund von Netzwerkproblemen.
- ✨ Bessere Nutzererfahrung: Die Kombination aus schnellerem Start und weniger Zwischenspeichern sorgt für eine flüssigere, nahtlose Interaktion für die Nutzer.
In dieser dreiteiligen Reihe stellen wir die leistungsstarken Dienstprogramme von Media3 zum (Vor-)Laden von Komponenten vor und gehen im Detail darauf ein.
- In Teil 1 behandeln wir die Grundlagen: die verschiedenen in Media3 verfügbaren Strategien für das Vorabladen, die Aktivierung von „PreloadConfiguration“ und die Einrichtung des „DefaultPreloadManager“, damit Ihre App Elemente vorab laden kann. Am Ende dieses Blogs sollten Sie in der Lage sein, Mediendateien mit der von Ihnen konfigurierten Rangfolge und Dauer vorab zu laden und abzuspielen.
- In Teil 2 werden wir uns mit fortgeschritteneren Themen zu DefaultPreloadManager befassen: Verwendung von Listenern für Analysen, produktionsreife Best Practices wie das Sliding-Window-Muster und benutzerdefinierte freigegebene Komponenten von DefaultPreloadManager und ExoPlayer.
- In Teil 3 gehen wir genauer auf das Datenträger-Caching mit DefaultPreloadManager ein.
Hier kommt das Vorabladen ins Spiel. 🦸♀️
Die Grundidee des Vorabladens ist einfach: Medieninhalte werden geladen, bevor sie benötigt werden. Wenn ein Nutzer zum nächsten Video wischt, sind die ersten Segmente des Videos bereits heruntergeladen und verfügbar und können sofort wiedergegeben werden.
Stellen Sie sich ein Restaurant vor. In einer gut besuchten Küche wird nicht erst auf eine Bestellung gewartet, bevor die Zwiebeln geschnitten werden. 🧅 Sie erledigen die Vorbereitungen im Voraus. Das Vorabladen ist die Vorbereitung für den Videoplayer.
Wenn das Vorabladen aktiviert ist, kann es dazu beitragen, die Latenz beim Beitritt zu minimieren, wenn ein Nutzer zum nächsten Element springt, bevor der Wiedergabepuffer das nächste Element erreicht. Die erste Periode 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 Samples sind sofort verfügbar und können dem Codec zum Rendern 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 Auswahl der richtigen API ist der erste Schritt.
1. Playlistelemente 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 stellen dem Player die vollständige Liste der Mediendateien über die Playlist APIs von ExoPlayer zur Verfügung und legen die PreloadConfiguration für den Player fest. Anschließend werden die nächsten Elemente in der Sequenz automatisch wie konfiguriert vorab geladen. Diese API versucht, die Join-Latenz zu optimieren, wenn ein Nutzer zum nächsten Element springt, bevor der Wiedergabepuffer bereits das nächste Element erreicht hat.
Das Vorabladen wird nur gestartet, wenn für die laufende Wiedergabe keine Medien geladen werden. Dadurch wird verhindert, dass es mit der primären Wiedergabe um Bandbreite konkurriert.
Wenn Sie sich immer noch nicht sicher sind, ob Sie Preloading benötigen, ist diese API eine gute, unkomplizierte Möglichkeit, es auszuprobieren.
player.preloadConfiguration =
PreloadConfiguration(/* targetPreloadDurationUs= */ 5_000_000L)Mit der obigen PreloadConfiguration versucht der Player, fünf Sekunden Medien für das nächste Element in der Playlist vorab zu laden.
Nachdem Sie die Funktion aktiviert haben, können Sie sie mit PreloadConfiguration.DEFAULT wieder deaktivieren:
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 zur aktuellen Position des Nutzers. Außerdem bietet sie eine differenzierte Kontrolle darüber, was vorab geladen werden soll. Das ist für komplexe Szenarien wie dynamische Feeds von Kurzvideos geeignet.
PreloadManager einrichten
Der 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 wiedergeben. Wenn Sie einen DefaultPreloadManager erstellen möchten, müssen Sie ein TargetPreloadStatusControl-Objekt übergeben, das der Preload-Manager abfragen kann, um zu ermitteln, 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 zugrunde liegenden Komponenten korrekt gemeinsam genutzt werden.
Geschafft! Sie haben jetzt einen Manager, der bereit ist, Anweisungen zu erhalten.
Dauer und Ranking mit TargetPreloadStatusControl konfigurieren
Was ist, wenn Sie beispielsweise 10 Sekunden eines Videos vorab laden möchten? Sie können die Position Ihrer Mediendateien im Karussell angeben. Der DefaultPreloadManager priorisiert das Laden der Elemente basierend darauf, wie nah sie sich an dem Element befinden, das der Nutzer gerade abspielt.
Wenn Sie festlegen möchten, wie viel des Elements vorab geladen werden soll, können Sie das mit dem zurückgegebenen „DefaultPreloadManager.PreloadStatus“ angeben.
Beispiel:
- Element A hat die höchste Priorität. Es werden 5 Sekunden des Videos geladen.
- Element B hat mittlere Priorität. Wenn Sie es erreichen, laden Sie 3 Sekunden des Videos.
- Element „C“ hat eine niedrigere Priorität, nur Tracks werden geladen.
- Punkt D hat eine noch niedrigere Priorität. Hier reicht es, wenn Sie sich vorbereiten.
- Alle anderen Elemente sind weit entfernt. Es wird nichts vorab geladen.
Mit dieser detaillierten Steuerung können Sie die Ressourcenauslastung 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: Mit „PreloadManager“ können sowohl das vorherige als auch das nächste Element vorab geladen werden, während „PreloadConfiguration“ nur die nächsten Elemente berücksichtigt.
Vorab geladene Elemente verwalten
Nachdem Sie den Manager erstellt haben, können Sie ihm mitteilen, woran er arbeiten soll. Wenn ein Nutzer durch einen Feed scrollt, werden die nächsten Videos identifiziert und dem Manager hinzugefügt. Die Interaktion mit dem PreloadManager ist eine zustandsgesteuerte Kommunikation zwischen Ihrer Benutzeroberfläche und der Preloading-Engine.
1. Mediendateien hinzufügen
Wenn Sie Ihren Feed füllen, müssen Sie den Manager über die Medien informieren, die er erfassen soll. 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 sich in der Vorabladeliste befinden. 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 ruft jetzt im Hintergrund Daten für diese MediaItem ab.
Nachdem du ein Element hinzugefügt hast, weise den Manager an, die neue Liste neu zu bewerten. Gib dabei einen Hinweis darauf, dass sich etwas geändert hat, z. B. dass ein Element hinzugefügt oder entfernt wurde oder dass der Nutzer ein neues Element abspielen möchte.
preloadManager.invalidate()
2. Element abrufen und wiedergeben
Hier kommt die Hauptwiedergabelogik. Wenn der Nutzer das Video abspielt, müssen Sie kein neues MediaSource-Objekt erstellen. Stattdessen fragen Sie die PreloadManager nach der bereits vorbereiteten Antwort. Du kannst die MediaSource mithilfe des MediaItem aus dem Preload Manager 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 dann 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 Vorabladen zur Wiedergabe wechseln und dabei die bereits im Arbeitsspeicher vorhandenen Daten verwenden. Dadurch wird die Startzeit verkürzt.
3. Aktuellen Index mit der Benutzeroberfläche synchronisieren
Da unser Feed / unsere Liste dynamisch sein kann, ist es wichtig, den PreloadManager über den aktuellen Wiedergabeindex zu informieren, damit er immer die Elemente priorisieren kann, die dem aktuellen Index am nächsten sind.
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 nicht mehr verfolgt werden müssen, 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. Release Manager
Wenn Sie den PreloadManager nicht mehr benötigen (z.B. wenn Ihre Benutzeroberfläche gelöscht wird), müssen Sie ihn freigeben, um seine Ressourcen freizugeben. Ein guter Ort dafür ist dort, wo du bereits die Ressourcen deines Players freigibst. Es wird empfohlen, den Manager vor dem Player freizugeben, da der Player weiter abgespielt werden kann, wenn Sie kein Preloading mehr benötigen.
// In your Activity's onDestroy() or Composable's onDispose preloadManager.release()
Demo zeigen
Sieh dir die Funktion live in Aktion an 👍
In der Demo unten sehen Sie rechts die Auswirkungen von PreloadManager mit schnelleren Ladezeiten, während links die vorhandene Umgebung zu sehen ist. Sie können sich auch das Codebeispiel für die Demo ansehen. (Bonus: Es wird auch die Startlatenz für jedes Video angezeigt.)
Wie geht es weiter?
Das war's auch schon mit Teil 1. Sie haben jetzt die Tools, um ein dynamisches Vorladesystem zu erstellen. Du kannst entweder PreloadConfiguration verwenden, um das nächste Element einer Playlist in ExoPlayer vorab zu laden, oder einen DefaultPreloadManager einrichten, Elemente spontan hinzufügen und entfernen, den Zielstatus für das Vorabladen konfigurieren und die vorab geladenen Inhalte für die Wiedergabe korrekt abrufen.
In Teil 2 gehen wir näher auf die DefaultPreloadManager ein. Wir sehen uns an, wie Sie auf Vorablade-Ereignisse warten, 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 Rückmeldung.
Bleib dran und mach deine App schneller! 🚀
-
ProduktneuigkeitenWillkommen zum zweiten Teil unserer dreiteiligen Reihe zum Vorabladen von Medien mit Media3. In dieser Reihe erfahren Sie, wie Sie in Ihren Android-Apps Medien mit hoher Reaktionsfähigkeit und niedriger Latenz erstellen.
Mayuri Khinvasara Khabya • Lesezeit: 9 Minuten -
ProduktneuigkeitenApps, die auf die kommende Android-Version ausgerichtet sind, können mit der Berechtigung WRITE_CONTACTS nicht mehr direkt in Kontakte schreiben.
Roxanna Aliabadi Walker • Lesezeit: 6 Minuten -
ProduktneuigkeitenDie Entwicklung von KI-Agenten schreitet rasant voran und die Android-Entwicklung erreicht einen spannenden neuen Meilenstein: von der unterstützenden Codevervollständigung hin zu KI-Agenten, die unter Ihrer Anleitung End-to-End-Aufgaben ausführen. Sie haben die volle Auswahl und Flexibilität bei den Modellen und Agents, die Sie verwenden.
Jason Buchel • Lesezeit: 3 Minuten
Lassen Sie sich Woche für Woche die neuesten Informationen zur Android-Entwicklung zusenden.