ExoPlayer udostępnia funkcję pobierania multimediów do odtwarzania offline. Najwięcej
zaleca się, aby pobieranie było możliwe nawet wtedy, gdy aplikacja znajduje się
w tle. W tych przypadkach aplikacja powinna podklasa: DownloadService
i
wysyłania do usługi poleceń w celu dodania, usunięcia i kontrolowania pobranych plików.
na diagramie poniżej widać główne klasy, które są z nim związane.
DownloadService
: zawija obiektDownloadManager
i przekazuje do niego polecenia. umożliwia działanie aplikacjiDownloadManager
nawet wtedy, gdy jest ona uruchomiona w tle.DownloadManager
: zarządza wieloma pobieraniem, wczytuje (i zapisuje) ich pliki od (i do)DownloadIndex
, rozpoczynając i zatrzymując pobieranie na podstawie dotyczące wymagań dotyczących m.in. połączenia sieciowego. Aby pobrać treści, menedżer zazwyczaj odczytuje dane pobierane zHttpDataSource
i wpisz go wCache
.DownloadIndex
: zachowuje stan pobierania.
Tworzenie usługi DownloadService
Aby utworzyć klasę DownloadService
, należy ją podklasyować i zaimplementować
metody abstrakcyjne:
getDownloadManager()
: zwraca wartośćDownloadManager
, która ma zostać użyta.getScheduler()
: zwraca opcjonalny elementScheduler
, który może ponownie uruchomić usługi, gdy są spełnione wymagania dotyczące oczekujących pobrań. ExoPlayer udostępnia te implementacje:PlatformScheduler
, które używa JobScheduler (minimum to 21). Zobacz zapoznaj się z wymaganiami dotyczącymi uprawnień aplikacji w dokumentacji javadocs PlatformScheduler.WorkManagerScheduler
, który korzysta z WorkManagera.
getForegroundNotification()
: zwraca powiadomienie, które wyświetla się, gdy usługa jest uruchomiona na pierwszym planie. Za pomocąDownloadNotificationHelper.buildProgressNotification
, aby utworzyć powiadomienie w domyślnym stylu.
Na koniec zdefiniuj usługę w pliku 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>
Zobacz DemoDownloadService
i AndroidManifest.xml
w ExoPlayer
z konkretnym przykładem.
Tworzenie Menedżera pobierania
Ten fragment kodu pokazuje, jak utworzyć instancję DownloadManager
,
które może zwrócić getDownloadManager()
w DownloadService
:
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);
Konkretny przykład znajdziesz w sekcji DemoUtil
w aplikacji w wersji demonstracyjnej.
Dodaję pobrany plik
Aby dodać pobrany plik, utwórz DownloadRequest
i wyślij go na
DownloadService
W przypadku strumieni adaptacyjnych użyj DownloadHelper
.
utwórz DownloadRequest
. Poniżej
pokazuje, jak utworzyć żądanie pobrania:
Kotlin
val downloadRequest = DownloadRequest.Builder(contentId, contentUri).build()
Java
DownloadRequest downloadRequest = new DownloadRequest.Builder(contentId, contentUri).build();
W tym przykładzie contentId
jest unikalnym identyfikatorem treści. W prostych przypadkach
contentUri
może często służyć jako contentId
, ale aplikacje są bezpłatne.
do każdego schematu identyfikatora, który najlepiej sprawdzi się w danym przypadku. DownloadRequest.Builder
ma też
kilku opcjonalnych ustawień. Na przykład można użyć setKeySetId
i setData
, aby:
ustawić DRM i dane niestandardowe, które aplikacja ma powiązać z pobranym plikiem;
. Typ MIME treści można też określić w polu setMimeType
,
jako wskazówkę w przypadkach, w których nie można wywnioskować typu treści na podstawie contentUri
.
Po utworzeniu prośbę można wysłać do DownloadService
, aby dodać
pobieranie:
Kotlin
DownloadService.sendAddDownload( context, MyDownloadService::class.java, downloadRequest, /* foreground= */ false )
Java
DownloadService.sendAddDownload( context, MyDownloadService.class, downloadRequest, /* foreground= */ false);
W tym przykładzie MyDownloadService
to podklasa aplikacji DownloadService
, a klasa
Parametr foreground
określa, czy usługa zostanie uruchomiona w
na pierwszym planie. Jeśli aplikacja jest już na pierwszym planie, parametr foreground
powinien być ustawiony na false
, bo DownloadService
będzie
umieścić się na pierwszym planie, jeśli stwierdzi, że ma do wykonania zadanie.
Usuwam pobrane
Aby usunąć pobrany plik, wyślij do DownloadService
polecenie usunięcia.
gdzie contentId
wskazuje pobrany plik:
Kotlin
DownloadService.sendRemoveDownload( context, MyDownloadService::class.java, contentId, /* foreground= */ false )
Java
DownloadService.sendRemoveDownload( context, MyDownloadService.class, contentId, /* foreground= */ false);
Możesz też usunąć wszystkie pobrane dane za pomocą
DownloadService.sendRemoveAllDownloads
Rozpoczynanie i zatrzymywanie pobierania
Pobieranie będzie kontynuowane tylko wtedy, gdy zostaną spełnione 4 warunki:
- Pobieranie nie ma powodu zatrzymania.
- Pobieranie nie jest wstrzymywane.
- Spełniono wymagania dotyczące pobierania plików. Wymagania mogą obejmować dotyczące dozwolonych typów sieci oraz tego, czy urządzenie być nieaktywne lub podłączone do ładowarki.
- Maksymalna liczba równoległych pobrań nie została przekroczona.
Wszystkie te warunki można kontrolować, wysyłając polecenia do
DownloadService
Ustawianie i usuwanie przyczyn zatrzymania pobierania
Możesz ustawić przyczynę zatrzymania pobierania jednego lub wszystkich plików:
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
może mieć dowolną wartość inną niż 0 (Download.STOP_REASON_NONE = 0
to
specjalną wartość, która oznacza, że pobieranie nie zostało zatrzymane). Aplikacje, które zawierają
Różne przyczyny zatrzymania pobierania mogą mieć różne wartości, aby śledzić
przyczyny zatrzymania pobierania. Ustawianie i usuwanie przyczyny zatrzymania dla wszystkich
pobierania działa tak samo jak ustawianie i usuwanie przyczyny zatrzymania
jednorazowe pobranie, z tym że parametr contentId
powinien mieć wartość null
.
Jeśli przyczyna zatrzymania pobierania jest inna niż zero, zostanie on umieszczony w sekcji
Download.STATE_STOPPED
stan. Przyczyny zatrzymania są zachowywane w
DownloadIndex
, a także są przechowywane w przypadku zakończenia procesu zgłaszania, a także
później.
Wstrzymywanie i wznawianie pobierania wszystkich plików
Pobieranie można wstrzymywać i wznawiać w następujący sposób:
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);
Po wstrzymaniu pobierania ich stan zmieni się na Download.STATE_QUEUED
.
W przeciwieństwie do ustawionych przyczyn zatrzymania ta metoda nie zachowuje żadnego stanu
zmian. Ma to wpływ tylko na stan środowiska wykonawczego DownloadManager
.
Konfigurowanie wymagań dotyczących postępu pobierania
Requirements
może służyć do określania ograniczeń, które muszą być spełnione w przypadku
pobrane pliki, aby kontynuować. Wymagania można określić, wywołując
DownloadManager.setRequirements()
podczas tworzenia DownloadManager
, na przykład
przykład powyżej. Można je również dynamicznie zmieniać, wysyłając polecenie
do 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);
Jeśli nie można kontynuować pobierania z powodu niespełniania wymagań,
będzie mieć stan Download.STATE_QUEUED
. Możesz przesłać zapytanie o niespełnione
DownloadManager.getNotMetRequirements()
.
Ustawianie maksymalnej liczby równoległego pobierania
Maksymalna liczba równoległych pobrań można ustawić, wywołując
DownloadManager.setMaxParallelDownloads()
Zwykle ma to miejsce, gdy
tworząc DownloadManager
, jak widać w przykładzie powyżej.
Gdy nie można kontynuować pobierania ze względu na maksymalną liczbę równoległych pobrań
są już w toku, będą w stanie Download.STATE_QUEUED
.
Pytanie dotyczące pobierania
Zapytanie DownloadIndex
elementu DownloadManager
może być wysyłane w przypadku stanu wszystkich
pobierania, w tym tych, które zakończyły się lub zakończyły się niepowodzeniem. DownloadIndex
można uzyskać, wywołując DownloadManager.getDownloadIndex()
. Kursor,
powtórzenia we wszystkich pobranych plikach można następnie uzyskać przez wywołanie
DownloadIndex.getDownloads()
Stan pojedynczego pobrania
można wysyłać zapytania, wywołując DownloadIndex.getDownload()
.
DownloadManager
udostępnia również DownloadManager.getCurrentDownloads()
, które
zwraca tylko stan bieżących (tj. nieukończonych lub nieudanych) pobrań. Ten
jest przydatna przy aktualizowaniu powiadomień i innych komponentów interfejsu, które wyświetlają
postęp i stan pobierania.
Słucham pobranych treści
Możesz dodać detektor do aplikacji DownloadManager
, aby otrzymywać informacje o bieżącej
zmiany stanu pobierania:
Kotlin
downloadManager.addListener( object : DownloadManager.Listener { // Override methods of interest here. } )
Java
downloadManager.addListener( new DownloadManager.Listener() { // Override methods of interest here. });
Zobacz temat DownloadManagerListener
w zajęciach DownloadTracker
w aplikacji w wersji demonstracyjnej
z konkretnego przykładu.
Odtwarzam pobrane treści
Odtwarzanie pobranych treści przypomina odtwarzanie treści online, z tą różnicą, że
dane są odczytywane z pobranego pliku Cache
, a nie przez sieć.
Aby odtworzyć pobrane treści, utwórz CacheDataSource.Factory
, używając tego samego elementu
Cache
instancję, która została użyta do pobrania i wstrzyknij ją do
DefaultMediaSourceFactory
podczas tworzenia odtwarzacza:
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();
Czy ta sama instancja odtwarzacza będzie także używana do odtwarzania niepobranych treści
interfejs CacheDataSource.Factory
powinien być skonfigurowany jako tylko do odczytu, aby uniknąć
pobieranie tych treści również podczas odtwarzania.
Po skonfigurowaniu odtwarzacza CacheDataSource.Factory
będzie on
mają dostęp do pobranych treści w celu ich odtwarzania. Odtworzenie pobranego pliku jest wtedy
Wystarczy przekazać odpowiednie MediaItem
do odtwarzacza. MediaItem
można uzyskać z Download
przy użyciu Download.request.toMediaItem
lub
bezpośrednio z usługi DownloadRequest
przy użyciu DownloadRequest.toMediaItem
.
Konfiguracja MediaSource
Poprzedni przykład udostępnia pamięć podręczną pobierania do odtwarzania wszystkich plików
MediaItem
Możesz też udostępnić pamięć podręczną pobierania dla
pojedyncze instancje MediaSource
, które mogą być przekazywane bezpośrednio do odtwarzacza:
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();
Pobieranie i odtwarzanie strumieni adaptacyjnych
Strumienie adaptacyjne (np. DASH, SmoothStreaming i HLS) zwykle zawierają wiele ścieżek multimedialnych. Często istnieje wiele ścieżek zawierających te same treści w różnych jakości (np. ścieżki wideo SD, HD i 4K). Może być też wiele ścieżek tego samego typu zawierających różne treści (np. wiele ścieżek audio w różnych językach).
W przypadku odtwarzania strumieniowego można skorzystać z selektora ścieżki, aby wybrać
odtwarzanych utworów. Podobnie DownloadHelper
może służyć do:
wybrać utwory do pobrania. Typowe użycie: DownloadHelper
wykonaj te czynności:
- Utwórz
DownloadHelper
, korzystając z jednego zDownloadHelper.forMediaItem
. Przygotuj pomocnik i zaczekaj na oddzwonienie.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);
- Opcjonalnie sprawdź domyślnie wybrane ścieżki za pomocą narzędzia
getMappedTrackInfo
igetTrackSelections
oraz wprowadź korekty za pomocąclearTrackSelections
,replaceTrackSelections
iaddTrackSelection
. - Utwórz
DownloadRequest
dla wybranych utworów, dzwoniąc pod numergetDownloadRequest
Prośba może zostać przekazana doDownloadService
w celu dodaj pobrany plik w sposób opisany powyżej. - Zwolnij pomocnik, używając polecenia
release()
.
Odtwarzanie pobranych treści adaptacyjnych wymaga skonfigurowania odtwarzacza i
przekazując odpowiednią wartość MediaItem
zgodnie z opisem powyżej.
Podczas tworzenia obiektu MediaItem
MediaItem.localConfiguration.streamKeys
musi być:
jest ustawione na dopasowanie do tych w DownloadRequest
, tak by odtwarzacz próbował tylko
odtworzyć podzbiór pobranych utworów. Zastosowanie
Download.request.toMediaItem
i DownloadRequest.toMediaItem
, aby utworzyć
MediaItem
zajmie się tym za Ciebie.