ExoPlayer bietet Funktionen zum Herunterladen von Medien für die Offlinewiedergabe. In den meisten
Anwendungsfällen sollten die Downloads auch dann fortgesetzt werden, wenn sich Ihre App im
Hintergrund. Für diese Anwendungsfälle sollte Ihre App die Klassen DownloadService
und
Befehle zum Hinzufügen, Entfernen und Steuern der Downloads an den Dienst senden. Die
Das folgende Diagramm zeigt die beteiligten Hauptklassen.
DownloadService
: Fügt eineDownloadManager
ein und leitet Befehle an diese weiter. Die ermöglicht die Ausführung vonDownloadManager
, auch wenn sich die App in im Hintergrund.DownloadManager
: Verwaltet mehrere Downloads und lädt (und speichert) ihre eigenen Status von (und an) einemDownloadIndex
, wobei Downloads basierend auf wie die Netzwerkverbindung usw. So laden Sie die liest der Manager in der Regel die von einemHttpDataSource
und schreiben Sie es in eineCache
.DownloadIndex
: Der Status der Downloads bleibt bestehen.
DownloadService erstellen
Um ein DownloadService
zu erstellen, erstellen Sie abgeleitete Klassen davon und implementieren Sie
abstrakte Methoden:
getDownloadManager()
: Gibt die zu verwendendeDownloadManager
zurück.getScheduler()
: Gibt ein optionalesScheduler
-Objekt zurück, das den wenn die Anforderungen für ausstehende Downloads erfüllt sind. ExoPlayer bietet folgende Implementierungen: <ph type="x-smartling-placeholder">- </ph>
PlatformScheduler
verwendet JobScheduler (Minimum API ist 21). Weitere Informationen finden Sie unter In der PlatformScheduler-Javadocs für die Anforderungen an App-BerechtigungenWorkManagerScheduler
verwendet WorkManager.
getForegroundNotification()
: Gibt eine Benachrichtigung zurück, die angezeigt wird, wenn der der Dienst im Vordergrund ausgeführt wird. Sie könnenDownloadNotificationHelper.buildProgressNotification
zum Erstellen Benachrichtigung im Standardstil.
Definieren Sie abschließend den Dienst in der Datei AndroidManifest.xml
:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC"/>
<application>
<service android:name="com.myapp.MyDownloadService"
android:exported="false"
android:foregroundServiceType="dataSync">
<!-- This is needed for Scheduler -->
<intent-filter>
<action android:name="androidx.media3.exoplayer.downloadService.action.RESTART"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</service>
</application>
Siehe DemoDownloadService
und AndroidManifest.xml
im ExoPlayer
Demo-App ein konkretes Beispiel.
DownloadManager erstellen
Das folgende Code-Snippet zeigt, wie eine DownloadManager
instanziiert wird.
Dieser kann von getDownloadManager()
in deinem DownloadService
zurückgegeben werden:
Kotlin
// Note: This should be a singleton in your app. val databaseProvider = StandaloneDatabaseProvider(context) // A download cache should not evict media, so should use a NoopCacheEvictor. val downloadCache = SimpleCache(downloadDirectory, NoOpCacheEvictor(), databaseProvider) // Create a factory for reading the data from the network. val dataSourceFactory = DefaultHttpDataSource.Factory() // Choose an executor for downloading data. Using Runnable::run will cause each download task to // download data on its own thread. Passing an executor that uses multiple threads will speed up // download tasks that can be split into smaller parts for parallel execution. Applications that // already have an executor for background downloads may wish to reuse their existing executor. val downloadExecutor = Executor(Runnable::run) // Create the download manager. val downloadManager = DownloadManager(context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor) // Optionally, properties can be assigned to configure the download manager. downloadManager.requirements = requirements downloadManager.maxParallelDownloads = 3
Java
// Note: This should be a singleton in your app. databaseProvider = new StandaloneDatabaseProvider(context); // A download cache should not evict media, so should use a NoopCacheEvictor. downloadCache = new SimpleCache(downloadDirectory, new NoOpCacheEvictor(), databaseProvider); // Create a factory for reading the data from the network. dataSourceFactory = new DefaultHttpDataSource.Factory(); // Choose an executor for downloading data. Using Runnable::run will cause each download task to // download data on its own thread. Passing an executor that uses multiple threads will speed up // download tasks that can be split into smaller parts for parallel execution. Applications that // already have an executor for background downloads may wish to reuse their existing executor. Executor downloadExecutor = Runnable::run; // Create the download manager. downloadManager = new DownloadManager( context, databaseProvider, downloadCache, dataSourceFactory, downloadExecutor); // Optionally, setters can be called to configure the download manager. downloadManager.setRequirements(requirements); downloadManager.setMaxParallelDownloads(3);
Ein konkretes Beispiel finden Sie in der Demo-App unter DemoUtil
.
Download hinzufügen
Wenn du einen Download hinzufügen möchtest, erstelle eine DownloadRequest
und sende sie an dein
DownloadService
. Bei adaptiven Streams verwenden Sie DownloadHelper
, um die
DownloadRequest
erstellen Die folgenden
Beispiel für die Erstellung einer Downloadanfrage:
Kotlin
val downloadRequest = DownloadRequest.Builder(contentId, contentUri).build()
Java
DownloadRequest downloadRequest = new DownloadRequest.Builder(contentId, contentUri).build();
In diesem Beispiel ist contentId
eine eindeutige Kennung für den Inhalt. In einfachen Fällen
contentUri
kann oft als contentId
verwendet werden, die Nutzung der Apps ist jedoch kostenlos
ID-Schema, das sich
am besten für ihren Anwendungsfall eignet. DownloadRequest.Builder
hat auch
einige optionale Setter. Beispielsweise können setKeySetId
und setData
für Folgendes verwendet werden:
DRM und benutzerdefinierte Daten festlegen,
die die App mit dem Download verknüpfen möchte,
. Der MIME-Typ des Inhalts kann auch mit setMimeType
angegeben werden,
als Hinweis in Fällen, in denen der Inhaltstyp nicht von contentUri
abgeleitet werden kann.
Nach der Erstellung kann die Anfrage an den DownloadService
gesendet werden, um den
Herunterladen:
Kotlin
DownloadService.sendAddDownload( context, MyDownloadService::class.java, downloadRequest, /* foreground= */ false )
Java
DownloadService.sendAddDownload( context, MyDownloadService.class, downloadRequest, /* foreground= */ false);
In diesem Beispiel ist MyDownloadService
die abgeleitete DownloadService
-Klasse der Anwendung und der
Der Parameter foreground
steuert, ob der Dienst im
im Vordergrund. Wenn deine App bereits im Vordergrund ausgeführt wird, ist der foreground
normalerweise auf false
gesetzt werden, weil DownloadService
sich selbst in den Vordergrund rückt, wenn es feststellt, dass es Arbeit zu erledigen hat.
Downloads werden entfernt
Um einen Download zu entfernen, senden Sie einen Befehl zum Entfernen an DownloadService
.
Dabei gibt contentId
den zu entfernenden Download an:
Kotlin
DownloadService.sendRemoveDownload( context, MyDownloadService::class.java, contentId, /* foreground= */ false )
Java
DownloadService.sendRemoveDownload( context, MyDownloadService.class, contentId, /* foreground= */ false);
Sie können alle heruntergeladenen Daten auch mit
DownloadService.sendRemoveAllDownloads
Downloads starten und beenden
Ein Download wird nur fortgesetzt, wenn vier Bedingungen erfüllt sind:
- Der Download hat keinen Stoppgrund.
- Downloads werden nicht pausiert.
- Die Voraussetzungen für den Fortschritt von Downloads sind erfüllt. Anforderungen können angeben, welche Netzwerktypen zulässig sind und ob das Gerät inaktiv oder an ein Ladegerät angeschlossen.
- Die maximale Anzahl paralleler Downloads wird nicht überschritten.
All diese Bedingungen können durch Senden von Befehlen an Ihren
DownloadService
Gründe für das Stoppen des Downloads festlegen und löschen
Sie können einen Grund für das Beenden eines oder aller Downloads angeben:
Kotlin
// Set the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService::class.java, contentId, stopReason, /* foreground= */ false ) // Clear the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService::class.java, contentId, Download.STOP_REASON_NONE, /* foreground= */ false )
Java
// Set the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService.class, contentId, stopReason, /* foreground= */ false); // Clear the stop reason for a single download. DownloadService.sendSetStopReason( context, MyDownloadService.class, contentId, Download.STOP_REASON_NONE, /* foreground= */ false);
stopReason
kann ein beliebiger Wert ungleich null sein (Download.STOP_REASON_NONE = 0
ist
ein spezieller Wert, d. h., der Download wird nicht angehalten). Apps mit
Mehrere Gründe für das Beenden von Downloads können unterschiedliche Werte verwenden, um den Überblick zu behalten.
warum die einzelnen Downloads gestoppt wurden. Stoppgrund für alle festlegen und löschen
funktioniert genauso wie das Festlegen und Löschen des Stoppgrunds
einzelner Download, außer dass contentId
auf null
gesetzt werden sollte.
Wenn ein Download einen Stoppgrund ungleich null hat, befindet er sich im
Download.STATE_STOPPED
. Stoppgründe bleiben im
DownloadIndex
und bleiben erhalten, wenn der Anwendungsprozess abgebrochen wird und
neu gestartet.
Alle Downloads anhalten und fortsetzen
Alle Downloads können so pausiert und fortgesetzt werden:
Kotlin
// Pause all downloads. DownloadService.sendPauseDownloads( context, MyDownloadService::class.java, /* foreground= */ false ) // Resume all downloads. DownloadService.sendResumeDownloads( context, MyDownloadService::class.java, /* foreground= */ false )
Java
// Pause all downloads. DownloadService.sendPauseDownloads(context, MyDownloadService.class, /* foreground= */ false); // Resume all downloads. DownloadService.sendResumeDownloads(context, MyDownloadService.class, /* foreground= */ false);
Wenn Downloads pausiert sind, haben sie den Status Download.STATE_QUEUED
.
Anders als beim Festlegen von Gründen für das Stoppen behält dieser Ansatz keinen Status bei.
Änderungen. Sie wirkt sich nur auf den Laufzeitstatus von DownloadManager
aus.
Voraussetzungen für den Fortschritt von Downloads festlegen
Mit Requirements
können Einschränkungen angegeben werden, die für
herunterladen, um fortzufahren. Die Anforderungen können durch Aufrufen von
DownloadManager.setRequirements()
beim Erstellen der DownloadManager
, wie in
Beispiel. Sie können auch dynamisch geändert werden, indem ein Befehl
zu DownloadService
:
Kotlin
// Set the download requirements. DownloadService.sendSetRequirements( context, MyDownloadService::class.java, requirements, /* foreground= */ false)
Java
// Set the download requirements. DownloadService.sendSetRequirements( context, MyDownloadService.class, requirements, /* foreground= */ false);
Wenn ein Download nicht fortgesetzt werden kann, weil die Anforderungen nicht erfüllt sind,
hat den Status Download.STATE_QUEUED
. Sie können die nicht erfüllten
mit DownloadManager.getNotMetRequirements()
.
Maximale Anzahl paralleler Downloads festlegen
Die maximale Anzahl paralleler Downloads kann durch Aufrufen von
DownloadManager.setMaxParallelDownloads()
Dies erfolgt normalerweise, wenn
beim Erstellen von DownloadManager
, wie im Beispiel oben.
Wenn ein Download nicht fortgesetzt werden kann, weil die maximale Anzahl paralleler Downloads
bereits ausgeführt werden, hat sie den Status Download.STATE_QUEUED
.
Downloads abfragen
Der DownloadIndex
einer DownloadManager
kann für den Status aller
Downloads, einschließlich abgeschlossener oder fehlgeschlagener Downloads. Das DownloadIndex
erhalten Sie durch Aufrufen von DownloadManager.getDownloadIndex()
. Ein Cursor, der
Iterationen für alle Downloads können dann abgerufen werden, indem
DownloadIndex.getDownloads()
Alternativ kann der Status eines einzelnen Downloads
kann durch Aufrufen von DownloadIndex.getDownload()
abgefragt werden.
DownloadManager
bietet auch DownloadManager.getCurrentDownloads()
, das
gibt nur den Status der aktuellen Downloads zurück (d.h. nicht abgeschlossen oder fehlgeschlagen). Dieses
-Methode ist nützlich, um Benachrichtigungen und andere UI-Komponenten zu aktualisieren,
Fortschritt und Status aktueller Downloads.
Downloads anhören
Sie können DownloadManager
einen Listener hinzufügen, der informiert wird, wenn
Änderungsstatus der Downloads:
Kotlin
downloadManager.addListener( object : DownloadManager.Listener { // Override methods of interest here. } )
Java
downloadManager.addListener( new DownloadManager.Listener() { // Override methods of interest here. });
Unter DownloadManagerListener
in der Klasse DownloadTracker
der Demo-App finden Sie
ein konkretes Beispiel.
Heruntergeladene Inhalte werden wiedergegeben
Das Abspielen heruntergeladener Inhalte funktioniert ähnlich wie die Wiedergabe von Onlineinhalten, mit folgenden Ausnahmen:
Daten werden aus dem Download-Cache
statt über das Netzwerk gelesen.
Um heruntergeladene Inhalte wiederzugeben, erstelle ein CacheDataSource.Factory
mit demselben
Cache
-Instanz, die zum Herunterladen verwendet wurde, und in dieses Element einfügen.
DefaultMediaSourceFactory
beim Erstellen des Players:
Kotlin
// Create a read-only cache data source factory using the download cache. val cacheDataSourceFactory: DataSource.Factory = CacheDataSource.Factory() .setCache(downloadCache) .setUpstreamDataSourceFactory(httpDataSourceFactory) .setCacheWriteDataSinkFactory(null) // Disable writing. val player = ExoPlayer.Builder(context) .setMediaSourceFactory( DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory) ) .build()
Java
// Create a read-only cache data source factory using the download cache. DataSource.Factory cacheDataSourceFactory = new CacheDataSource.Factory() .setCache(downloadCache) .setUpstreamDataSourceFactory(httpDataSourceFactory) .setCacheWriteDataSinkFactory(null); // Disable writing. ExoPlayer player = new ExoPlayer.Builder(context) .setMediaSourceFactory( new DefaultMediaSourceFactory(context).setDataSourceFactory(cacheDataSourceFactory)) .build();
Wenn dieselbe Playerinstanz auch für die Wiedergabe nicht heruntergeladener Inhalte verwendet wird
sollte die CacheDataSource.Factory
als schreibgeschützt konfiguriert werden, um zu vermeiden,
während der Wiedergabe
auch diese Inhalte heruntergeladen werden.
Sobald der Player mit CacheDataSource.Factory
konfiguriert wurde, wird er
auf die heruntergeladenen Inhalte zur Wiedergabe zugreifen können. Das Abspielen eines Downloads
indem du einfach die entsprechende MediaItem
an den Spieler übergibst. Ein MediaItem
können aus einem Download
mit Download.request.toMediaItem
abgerufen werden oder
mit DownloadRequest.toMediaItem
direkt von einem DownloadRequest
abrufen.
MediaSource-Konfiguration
Mit dem vorherigen Beispiel wird der Download-Cache für die Wiedergabe aller
MediaItem
Sek. Sie können den Download-Cache auch für andere
einzelne MediaSource
-Instanzen, die direkt an den Spieler übergeben werden können:
Kotlin
val mediaSource = ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(MediaItem.fromUri(contentUri)) player.setMediaSource(mediaSource) player.prepare()
Java
ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory) .createMediaSource(MediaItem.fromUri(contentUri)); player.setMediaSource(mediaSource); player.prepare();
Adaptive Streams herunterladen und wiedergeben
Adaptive Streams (z.B. DASH, SmoothStreaming und HLS) enthalten normalerweise mehrere Medientracks. Oft gibt es mehrere Tracks, die denselben Inhalt mit unterschiedlichen Qualitäten (z. B. SD-, HD- und 4K-Videotracks) Möglicherweise gibt es auch Mehrere Tracks desselben Typs mit unterschiedlichen Inhalten (z.B. mehrere Audiotracks in verschiedenen Sprachen).
Bei Streaming-Wiedergaben kann mit einer Titelauswahl festgelegt werden, welche der
Titel abgespielt werden. Ähnlich kann ein DownloadHelper
zum Herunterladen verwendet werden, um
auswählen, welche Titel heruntergeladen werden sollen. Typische Nutzung eines DownloadHelper
führt dazu folgende Schritte aus:
- Erstelle einen
DownloadHelper
mit einer derDownloadHelper.forMediaItem
. Bereiten Sie das Hilfsprogramm vor und warten Sie auf den Rückruf.Kotlin
val downloadHelper = DownloadHelper.forMediaItem( context, MediaItem.fromUri(contentUri), DefaultRenderersFactory(context), dataSourceFactory ) downloadHelper.prepare(callback)
Java
DownloadHelper downloadHelper = DownloadHelper.forMediaItem( context, MediaItem.fromUri(contentUri), new DefaultRenderersFactory(context), dataSourceFactory); downloadHelper.prepare(callback);
- Optional: Inspizieren Sie die standardmäßig ausgewählten Tracks mit
getMappedTrackInfo
. undgetTrackSelections
und nehmen Sie Anpassungen mitclearTrackSelections
vor,replaceTrackSelections
undaddTrackSelection
. - Erstelle eine
DownloadRequest
für die ausgewählten Tracks, indem du folgenden Befehl aufrufst:getDownloadRequest
. Die Anfrage kann anDownloadService
übergeben werden an fügen Sie den Download wie oben beschrieben hinzu. - Geben Sie das Hilfsprogramm mit
release()
frei.
Für die Wiedergabe heruntergeladener adaptiver Inhalte müssen der Player und
Übergeben des entsprechenden MediaItem
wie oben beschrieben.
Beim Erstellen von MediaItem
muss MediaItem.localConfiguration.streamKeys
mit denen im DownloadRequest
übereinstimmen, sodass der Spieler nur versucht,
die heruntergeladenen Titel wiedergeben. Mit
Download.request.toMediaItem
und DownloadRequest.toMediaItem
zum Erstellen von
MediaItem
übernimmt das für Sie.