ExoPlayer,泛化 SimpleCache 行为

ExoPlayer, generalize SimpleCache behaviour

我正在使用 ExoPlayer 2 播放来自网络的音乐。现在我想用漂亮的SimpleCacheclass来缓存下载的音乐。我的问题如下:每次我请求播放歌曲时,服务器 returns 都会给我一个不同的 URL(也是同一首歌曲),它被 SimpleCache 用作密钥。因此,SimpleCache 为每个 URL 创建一个新的缓存文件(即同一首歌曲的不同文件)。

如果有一种方法可以询问我为特定 url 生成的缓存文件的密钥是什么,那就太好了。你知道这样做的方法吗?

SimpleCache class 是 final,所以我不能覆盖它的方法。


编辑,粗略的解决方案:
我创建了一个 CacheDataSource 的副本,并在方法 open(DataSpec) 中更改了这一行,它负责生成密钥:

key = dataSpec.key != null ? dataSpec.key : uri.toString();

由于一些 uri 的参数,我可以生成相同的密钥,这些参数对于为同一首歌曲检索的每个 url 都是相等的。这个解决方案解决了我的问题,但并不是对所有可能的情况都如此通用和可利用。

CacheDataSource 已按照 this comment 中的说明使用:

private DataSource.Factory buildDataSourceFactory(final boolean useBandwidthMeter) {
    return new DataSource.Factory() {
        @Override
        public DataSource createDataSource() {
            LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(100 * 1024 * 1024);
            SimpleCache simpleCache = new SimpleCache(new File(getCacheDir(), "media_cache"), evictor);
            return new CacheDataSource(
                simpleCache,
                buildMyDataSourceFactory(useBandwidthMeter).createDataSource(),
                CacheDataSource.FLAG_BLOCK_ON_CACHE,
                10 * 1024 * 1024
            );
        }
    };
}

private DefaultDataSource.Factory buildMyDataSourceFactory(boolean useBandwidthMeter) {
    return new DefaultDataSourceFactory(PlayerActivity.this, userAgent, useBandwidthMeter ? BANDWIDTH_METER : null);
}

这是解决方案(在 exoplayer 2.10.2 上工作,但不确定是否适用于早期版本)。 要创建您的来源:

DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(context,
                Util.getUserAgent(context, getString(R.string.app_name)));

 CacheDataSourceFactory cacheDataSourceFactory =
                new CacheDataSourceFactory(downloadUtil.getDownloadCache(context), dataSourceFactory,
                        new FileDataSourceFactory(),
                        new CacheDataSinkFactory(downloadUtil.getDownloadCache(context), CacheDataSink.DEFAULT_FRAGMENT_SIZE),
                        0,null,new CacheKeyProvider());

ProgressiveMediaSource mediaSource = new ProgressiveMediaSource.Factory(cacheDataSourceFactory).createMediaSource(your_uri);

其中 CacheKeyProvider() 是您自己实现的 CacheKeyFactory。 class 将定义将用作密钥的内容。我的看起来像这样:

public class CacheKeyProvider implements CacheKeyFactory 
{

    @Override
    public String buildCacheKey(DataSpec dataSpec) {
        if (dataSpec.key!=null) return dataSpec.key;
        else return generate_key(dataSpec.uri);
    }

    private String generate_key(Uri uri){
        String string = uri.toString();
        String[] parts = string.split("\?");
        String part1 = parts[0];
        String part2 = parts[1];
        return part1;
    }
}

在我的例子中,当我的 url 发生变化时,我正在检索任何没有改变的东西,并将其用作密钥。

从 ExoPlayer 2.10.0 开始,它添加了 ProgressiveMediaSource class,它取代了 ExtractorMediaSource(已弃用)。 使用 Factory class 创建 ProgressiveMediaSource 时,您可以调用方法 setCustomCacheKey(String).

它正是我所需要的!