ExoPlayer的缓存- 一 使用简介

ExoPlayer 的 缓存-- 一 使用简介

原文链接

ExoPlayer 提供了媒体离线下载功能。在大多数用例中,即使应用程序在后台,也可以继续下载。应用实现这个工呢,应用程序应该继承子类DownloadService 并实例化,并向DownloadService发送命令以添加、删除和控制下载。下图显示了涉及的主要类。

image.png

图 1.下载媒体的类。箭头方向表示数据流向。

  • DownloadService: 包装 一个DownloadManager并将命令转发给它。DownloadManager即使应用程序在后台,该服务也允许继续运行。
  • DownloadManager:管理多个下载,并使用DownloadIndex 加载 存储它们的状态,根据网络连接等要求启动和停止下载等。要下载内容,DownloadManager通常会读取从 HttpDataSource 下载的数据 ,并将其写入Cache.
  • DownloadIndex:保存下载状态。

创建下载服务

要创建DownloadService,需要对其进行子类化并实现其抽象方法:

  • getDownloadManager():返回要使用的DownloadManager

  • getScheduler(): 返回一个可选 Scheduler
    

    当满足挂起下载进度所需的要求时,它可以重新启动服务。ExoPlayer 提供了这些实现:

    • PlatformScheduler,它使用JobScheduler(最低 API 为 21)。有关应用权限要求,请参阅PlatformScheduler javadocs。
    • WorkManagerScheduler,它使用WorkManager。
  • getForegroundNotification():返回服务在前台运行时显示的通知。您可以使用 DownloadNotificationHelper.buildProgressNotification默认样式创建通知。

最后,需要在AndroidManifest.xml文件中定义服务:


  
  
    
    
  

DemoDownloadService有关具体示例,请参见AndroidManifest.xmlExoPlayer 演示应用程序。

创建下载管理器

以下代码片段演示了如何实例化 一个 DownloadManager,可以在 实例化的DownloadService 中的getDownloadManager() 返回。

// 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,如本页下方所述。以下示例显示了如何创建下载请求:

DownloadRequest downloadRequest =
    new DownloadRequest.Builder(contentId, contentUri).build();

其中contentId是内容的唯一标识符。在一般的情况下, contentUri通常可以用作contentId,但是应用程序可以自由使用最适合其用例的任何 ID 方案。DownloadRequest.Builder还有一些可选的设置器。例如,setKeySetIdsetData可用于分别设置应用希望与下载关联的 DRM 和自定义数据。也可以使用 指定内容的 MIME 类型setMimeType,在contentUri无法推断媒体类型的情况下使用。

创建后,可以将请求发送DownloadService到添加下载:

DownloadService.sendAddDownload(
    context,
    MyDownloadService.class,
    downloadRequest,
    /* foreground= */ false)

其中MyDownloadService是app的DownloadService子类, foreground参数控制服务是否会在前台启动。如果您的应用程序已经在前台,那么该foreground 参数通常应该设置为false,因为DownloadService如果它确定它有工作要做,它将把自己置于前台。

删除下载

可以通过向 发送删除命令来删除下载DownloadService,其中contentId标识要删除的下载:

DownloadService.sendRemoveDownload(
    context,
    MyDownloadService.class,
    contentId,
    /* foreground= */ false)

您还可以使用 删除所有下载的数据 DownloadService.sendRemoveAllDownloads

开始和停止下载

满足下面四个条件,下载才会进行:

  • 下载没有停止原因。
  • 下载不会暂停。
  • 满足下载进度的要求。需求可以指定对允许的网络类型的约束,以及设备是否应该空闲或连接到充电器。
  • 未超过最大并行下载数。

所有这些条件都可以通过 DownloadService 控制

设置和清除下载停止原因

可以设置一个或所有下载停止的原因:

// 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

设置停止原因不会删除下载。部分下载将被保留,清除停止原因将导致下载继续。

当下载有非 STOP_REASON_NONE 原因时,它将处于 Download.STATE_STOPPED状态。停止原因 DownloadIndex保留在 中,如果应用程序进程被杀死并稍后重新启动,则保留原因。

暂停和恢复所有下载

所有下载都可以按如下方式暂停和恢复:

// 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

// Set the download requirements.
DownloadService.sendSetRequirements(
    context,
    MyDownloadService.class,
    requirements,
    /* foreground= */ false);

当由于不满足要求而无法进行下载时,它将处于Download.STATE_QUEUED状态。您可以使用 查询未满足的要求DownloadManager.getNotMetRequirements()

设置最大并行下载数

可以通过调用来设置最大并行下载数 DownloadManager.setMaxParallelDownloads()。这通常在创建 时完成DownloadManager,如上例所示。

当由于已达到最大并行下载数而无法继续下载时,它将处于Download.STATE_QUEUED状态。

查询下载

可以查询所有下载的状态,包括已完成或失败的下载DownloadIndex。 可以通过调用DownloadManager获得。然后可以通过调用来获得遍历所有下载的游标 。或者,可以通过调用查询单次下载的状态。DownloadIndex``DownloadManager.getDownloadIndex()``DownloadIndex.getDownloads()``DownloadIndex.getDownload()

DownloadManager还提供DownloadManager.getCurrentDownloads(),它只返回当前(即未完成或失败)下载的状态。此方法对于更新通知和其他显示当前下载进度和状态的 UI 组件很有用。

监听下载

您可以添加一个侦听器以DownloadManager在当前下载更改状态时收到通知:

downloadManager.addListener(
    new DownloadManager.Listener() {
      // Override methods of interest here.
    });

DownloadManagerListener在演示应用程序的DownloadTracker类中查看具体示例。

下载进度更新不会触发对DownloadManager.Listener. 要更新显示下载进度的 UI 组件,您应该DownloadManager以所需的更新速率定期查询。DownloadService 包含一个示例,它会定期更新服务前台通知。

播放下载的内容

播放下载的内容类似于播放在线内容,不同之处在于数据是从下载中读取的,Cache而不是通过网络读取的。

不要尝试直接从下载目录中读取文件,这一点很重要。相反,请使用如下所述的 ExoPlayer 库类。

要播放下载的内容,CacheDataSource.Factory请使用与下载相同的 实例创建一个,并在构建播放器时Cache将其注入 :DefaultMediaSourceFactory

// 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(cacheDataSourceFactory))
    .build();

如果相同的播放器实例也将用于播放未下载的内容,CacheDataSource.Factory则应将其配置为只读,以避免在播放期间也下载该内容。

一旦播放器配置了CacheDataSource.Factory,它将可以访问下载的内容进行播放。播放下载就像将对应MediaItem的文件传递给播放器一样简单。一个MediaItem 可以从Download 获得Download.request.toMediaItem,也可以直接从DownloadRequest获得DownloadRequest.toMediaItem

媒体源配置

上面的示例使下载缓存可用于所有 MediaItem 的播放。也可以使下载缓存用于单个MediaSource实例,可以直接传递给播放器:

ProgressiveMediaSource mediaSource =
    new ProgressiveMediaSource.Factory(cacheDataSourceFactory)
        .createMediaSource(MediaItem.fromUri(contentUri));
player.setMediaSource(mediaSource);
player.prepare();

下载和播放自适应流

自适应流(例如 DASH、SmoothStreaming 和 HLS)通常包含多个媒体轨道。通常有多个轨道包含不同质量的相同内容(例如标清、高清和 4K 视频轨道)。也可能有多个相同类型的轨道包含不同的内容(例如,不同语言的多个音轨)。

对于流式播放,可以使用Track选择器来选择播放哪些Track。类似地,对于下载,DownloadHelper可以使用 Track选择器来选择下载哪些曲目。DownloadHelper 典型用法遵循以下步骤:

  1. DownloadHelper 使用其中一种方法构建一个 DownloadHelper.forMediaItem。 准备DownloadHelper并等待callback。

    DownloadHelper downloadHelper =
        DownloadHelper.forMediaItem(
            context,
            MediaItem.fromUri(contentUri),
            new DefaultRenderersFactory(context),
            dataSourceFactory);
    downloadHelper.prepare(myCallback);
    
  2. 或者,使用 和 检查默认选定的轨道, 并使用getMappedTrackInfogetTrackSelections进行调整。clearTrackSelections``replaceTrackSelections``addTrackSelection

  3. DownloadRequest通过调用为选定的Track 创建一个getDownloadRequest。如上所述,可以将请求传递给您DownloadService以添加下载。

  4. 使用 释放助手release()

播放下载的自适应内容需要配置播放器并传递相应的MediaItem,如上所述。

构建时MediaItemMediaItem.playbackProperties.streamKeys必须设置为与 中的匹配,DownloadRequest以便播放器仅尝试播放已下载的曲目子集。使用 Download.request.toMediaItemDownloadRequest.toMediaItem构建 MediaItem会为您解决这个问题。

你可能感兴趣的:(ExoPlayer的缓存- 一 使用简介)