ExoPlayer 提供下載媒體以供離線播放的功能。大多數
那麼,即使您的應用程式位於下列國家/地區,仍建議您繼續下載
背景。針對這些用途,應用程式應將 DownloadService
和
傳送指令給服務,以便新增、移除及控管下載內容。
下圖顯示涉及的主要類別。
DownloadService
:納入DownloadManager
並將指令轉送至該函式。 服務允許DownloadManager
即使應用程式處於執行狀態時也繼續執行 背景工作。DownloadManager
:管理多個下載、載入 (及儲存) 這些項目 在DownloadIndex
之間 (以及到) 的狀態,根據 網路連線等需求如要下載 管理員通常會讀取HttpDataSource
並寫入Cache
。DownloadIndex
:保留下載狀態。
建立下載服務
如要建立 DownloadService
,請將其設為子類別,並實作
抽象方法:
getDownloadManager()
:傳回要使用的DownloadManager
。getScheduler()
:傳回選用的Scheduler
,可重新啟動 服務。 ExoPlayer 提供以下實作方式:PlatformScheduler
,使用 JobScheduler (最低 API 為 21)。詳情請見 PlatformScheduler javadocs 中的應用程式權限要求。WorkManagerScheduler
,使用 WorkManager。
getForegroundNotification()
:傳回要在 服務正在前景執行。別擔心!您可以使用DownloadNotificationHelper.buildProgressNotification
即可建立 採用預設樣式的通知
最後,在 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>
在 ExoPlayer 中查看 DemoDownloadService
和 AndroidManifest.xml
以便查看具體範例
建立 downloadManager
下列程式碼片段示範如何將 DownloadManager
執行個體化。
可在 DownloadService
中由 getDownloadManager()
傳回:
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);
如需具體範例,請參閱試用版應用程式中的 DemoUtil
。
正在新增下載
如要新增下載內容,請建立DownloadRequest
並傳送至
DownloadService
。針對自動調整式串流,請使用 DownloadHelper
建構 DownloadRequest
。下列
範例說明如何建立下載要求:
Kotlin
val downloadRequest = DownloadRequest.Builder(contentId, contentUri).build()
Java
DownloadRequest downloadRequest = new DownloadRequest.Builder(contentId, contentUri).build();
在這個範例中,contentId
是內容的專屬 ID。簡單來說,
contentUri
通常可做為 contentId
,但應用程式可免費使用
挑選最適合其用途的 ID 配置DownloadRequest.Builder
也擁有
一些選用的 setter。舉例來說,setKeySetId
和 setData
可用於
設定應用程式要與下載內容連結的 DRM 和自訂資料。
。您也可以使用 setMimeType
指定內容的 MIME 類型,
做為無法從 contentUri
推斷內容類型時提示。
建立後,該要求可傳送至 DownloadService
,以新增
下載:
Kotlin
DownloadService.sendAddDownload( context, MyDownloadService::class.java, downloadRequest, /* foreground= */ false )
Java
DownloadService.sendAddDownload( context, MyDownloadService.class, downloadRequest, /* foreground= */ false);
在此範例中,MyDownloadService
是應用程式的 DownloadService
子類別,
foreground
參數會控制是否要在
前景。如果應用程式已在前景運作,則 foreground
參數通常會設為 false
,因為 DownloadService
等到系統判定有運作時,再於前景執行。
正在移除下載內容
如要移除下載項目,請將移除指令傳送至 DownloadService
。
其中 contentId
代表要移除的下載項目:
Kotlin
DownloadService.sendRemoveDownload( context, MyDownloadService::class.java, contentId, /* foreground= */ false )
Java
DownloadService.sendRemoveDownload( context, MyDownloadService.class, contentId, /* foreground= */ false);
你也可以使用
DownloadService.sendRemoveAllDownloads
。
開始及停止下載
只有在符合以下四個條件時,系統才會開始下載:
- 下載作業沒有停止原因。
- 並未暫停下載。
- 符合下載進度的條件。規定可指定 限制網路類型,以及裝置 裝置處於閒置狀態或連接到充電器時。
- 未超過同時下載數量上限。
這些條件均可傳送指令到
DownloadService
。
設定及清除下載停止原因
您可以為單次或所有下載作業設定停止的原因:
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
可以是任何非零的值 (Download.STOP_REASON_NONE = 0
為
特殊值,表示下載不會停止)。符合下列條件的應用程式:
可能會基於多種原因而停止下載
中說明瞭每次下載停止的原因設定並清除全部的停止原因
下載功能就像設定及清除停止原因
單一下載,但 contentId
應設為 null
。
如果下載的原因不是零,就會維持在
Download.STATE_STOPPED
狀態。停靠站原因會保留在
DownloadIndex
等等。如果應用程式程序終止,
然後重新啟動
暫停及繼續下載
您可以按照以下方式暫停並恢復所有下載作業:
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);
暫停下載時,將處於 Download.STATE_QUEUED
狀態。
與設定停止原因不同,此方法不會保留任何狀態
並輸入變更內容這只會影響 DownloadManager
的執行階段狀態。
設定下載進度的相關規定
Requirements
可用來指定必須符合的限制條件
下載內容,才能繼續使用。您可以呼叫
DownloadManager.setRequirements()
建立 DownloadManager
,如
如上範例所示也可以傳送指令來動態變更
至 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);
如果下載作業不符合規定而無法繼續下載,
將處於 Download.STATE_QUEUED
狀態您可以查詢未達成的目標
DownloadManager.getNotMetRequirements()
的需求。
設定平行下載數量上限
如要設定平行下載數量上限,請呼叫
DownloadManager.setMaxParallelDownloads()
。這項作業通常會在
建立 DownloadManager
,如上述範例所示。
當平行下載數量上限導致下載作業無法繼續時
已在進行中,將會處於 Download.STATE_QUEUED
狀態。
查詢下載內容
您可以查詢 DownloadManager
的 DownloadIndex
,以取得所有
下載的內容,包括已完成或失敗的下載內容。DownloadIndex
呼叫 DownloadManager.getDownloadIndex()
即可取得。遊標
所有下載皆會疊代
DownloadIndex.getDownloads()
。或者,單一下載的狀態
可以呼叫 DownloadIndex.getDownload()
進行查詢
DownloadManager
也提供 DownloadManager.getCurrentDownloads()
,
只會傳回目前下載狀態 (亦即未完成或失敗) 的狀態。這個
方法來更新通知以及其他顯示畫面的 UI 元件
目前下載項目的進度和狀態。
聆聽下載內容
您可以將事件監聽器新增至 DownloadManager
,以於目前何時收到通知
下載變更狀態:
Kotlin
downloadManager.addListener( object : DownloadManager.Listener { // Override methods of interest here. } )
Java
downloadManager.addListener( new DownloadManager.Listener() { // Override methods of interest here. });
請參閱試用版應用程式 DownloadTracker
類別中 DownloadManagerListener
:
具體範例
播放已下載的內容
下載的內容和播放線上內容類似,差別在於
資料會從下載的 Cache
讀取,而不是透過網路讀取。
如要播放下載的內容,請CacheDataSource.Factory
使用
用於下載的 Cache
執行個體,並插入該執行個體
DefaultMediaSourceFactory
(建立播放器時):
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();
如果相同的播放器例項也會用於播放未下載內容
那麼 CacheDataSource.Factory
應設為唯讀,
也會在播放期間下載這些內容
玩家使用 CacheDataSource.Factory
完成設定後,
可存取下載的內容。然後開始下載
就如同傳遞對應的 MediaItem
給玩家一樣簡單。MediaItem
可以使用 Download.request.toMediaItem
從 Download
取得,或
直接從 DownloadRequest
使用 DownloadRequest.toMediaItem
。
MediaSource 設定
在上述範例中,您可以播放下載快取
MediaItem
秒。您也可以讓下載快取
個別的 MediaSource
例項,可以直接傳遞至播放器:
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();
下載及播放自動調整式串流
自動調整串流 (例如 DASH、SmoothStreaming 和 HLS) 通常包含多個 媒體曲目通常會在多個音軌中提供相同內容 不同畫質 (例如 SD 標準畫質、HD 高畫質和 4K 影片軌)。除此之外 包含不同內容的多個相同類型的多個音軌 (例如, 不同語言的音軌)。
以串流播放來說,曲目選取器可用來選擇
播放曲目。同樣地,在下載時,DownloadHelper
可用來
選擇您要下載的曲目。DownloadHelper
的一般用量
步驟如下:
- 使用其中一個
DownloadHelper.forMediaItem
建構DownloadHelper
方法。準備輔助程式並等待回呼。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);
- 視需要使用
getMappedTrackInfo
檢查預設所選測試群組 和getTrackSelections
,並使用clearTrackSelections
、replaceTrackSelections
和addTrackSelection
。 - 呼叫 ,為所選音軌建立
DownloadRequest
getDownloadRequest
。要求可傳遞至您的DownloadService
,以便: 按照上述說明新增下載內容。 - 使用
release()
釋出輔助程式。
必須設定播放器和
按照上述方式傳遞對應的 MediaItem
。
建構 MediaItem
時,必須採用 MediaItem.localConfiguration.streamKeys
設為與 DownloadRequest
中的值相符,讓玩家只會嘗試
播放已下載的部分曲目。使用
Download.request.toMediaItem
和 DownloadRequest.toMediaItem
用來建構
「MediaItem
」會為你處理這個問題。