ExoPlayer 2.18.0版本实现类Glide视频缓存功能问题咨询
你遇到的类缺失、API不匹配问题均来自ExoPlayer大版本迭代的API重构,2.18版本已经完全移除了旧版的ExtractorMediaSource、ExoPlayerFactory、旧版DataSourceFactory相关类,直接按以下步骤实现即可达到类Glide的自动缓存效果,缓存文件存储在应用专属缓存目录,完全适配Android 9+隐私规则,无需额外申请存储权限,也不需要引入第三方缓存库。
前置说明
你当前引入的ExoPlayer依赖已经包含所有缓存相关模块,无需新增依赖。第三方AndroidVideoCache库已停止维护多年,存在系统兼容、代理冲突等问题,不建议使用,直接用ExoPlayer官方自带的缓存实现即可。
第一步:初始化全局唯一缓存实例
SimpleCache实例必须全局单例,重复创建会触发文件锁冲突、缓存失效甚至崩溃,在自定义Application类中完成初始化:
Kotlin 实现
class MyApp : Application() { companion object { // 可自行调整缓存上限,示例设置为1GB private const val MAX_CACHE_SIZE = 1024 * 1024 * 1024L lateinit var videoCache: SimpleCache private set } override fun onCreate() { super.onCreate() // 缓存目录放在应用私有缓存路径下,无权限问题 val cacheDir = File(cacheDir, "exo_video_cache") if (!cacheDir.exists()) cacheDir.mkdirs() // 采用LRU淘汰策略,超出缓存上限自动删除最久未使用的缓存文件 val evictor = LeastRecentlyUsedCacheEvictor(MAX_CACHE_SIZE) val dbProvider = StandaloneDatabaseProvider(this) videoCache = SimpleCache(cacheDir, evictor, dbProvider) } }
Java 实现
public class MyApp extends Application { private static final long MAX_CACHE_SIZE = 1024 * 1024 * 1024L; private static SimpleCache videoCache; @Override public void onCreate() { super.onCreate(); File cacheDir = new File(getCacheDir(), "exo_video_cache"); if (!cacheDir.exists()) cacheDir.mkdirs(); CacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(MAX_CACHE_SIZE); DatabaseProvider dbProvider = new StandaloneDatabaseProvider(this); videoCache = new SimpleCache(cacheDir, evictor, dbProvider); } public static SimpleCache getVideoCache() { return videoCache; } }
初始化完成后,记得在AndroidManifest.xml的<application>标签下添加android:name=".MyApp"属性,保证应用启动时初始化缓存实例。
第二步:构造支持缓存的数据源工厂
替换旧示例中已经废弃的CacheDataSourceFactory,按新版API构造带缓存逻辑的数据源:
Kotlin 实现
// 基础网络数据源 val httpDataSourceFactory = DefaultHttpDataSource.Factory() .setUserAgent("your-app-name") .setAllowCrossProtocolRedirects(true) // 包装为缓存数据源 val cachedDataSourceFactory = CacheDataSource.Factory() .setCache(MyApp.videoCache) .setUpstreamDataSourceFactory(httpDataSourceFactory) // 缓存策略:优先读取本地缓存,缓存不存在时拉取网络并自动写入缓存,缓存读取失败时自动回退到网络请求 .setFlags(CacheDataSource.FLAG_BLOCK_ON_CACHE or CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)
Java 实现
DefaultHttpDataSource.Factory httpDataSourceFactory = new DefaultHttpDataSource.Factory() .setUserAgent("your-app-name") .setAllowCrossProtocolRedirects(true); CacheDataSource.Factory cachedDataSourceFactory = new CacheDataSource.Factory() .setCache(MyApp.getVideoCache()) .setUpstreamDataSourceFactory(httpDataSourceFactory) .setFlags(CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR);
第三步:初始化播放器、构造媒体源
旧版ExtractorMediaSource已被ProgressiveMediaSource替代,对应普通MP4、MOV等渐进式视频的播放逻辑如下:
Kotlin 实现
// 初始化轨道选择器 val trackSelector = DefaultTrackSelector(this) // 2.18版本直接通过Builder构造ExoPlayer,无需旧版ExoPlayerFactory val player = ExoPlayer.Builder(this) .setTrackSelector(trackSelector) .build() // 构造带缓存的媒体源 val mediaSource = ProgressiveMediaSource.Factory(cachedDataSourceFactory) .createMediaSource(MediaItem.fromUri(yourVideoUrl)) // 绑定播放器到控件、准备播放 playerView.player = player player.setPlayWhenReady(true) player.setMediaSource(mediaSource) player.prepare()
Java 实现
DefaultTrackSelector trackSelector = new DefaultTrackSelector(this); ExoPlayer player = new ExoPlayer.Builder(this) .setTrackSelector(trackSelector) .build(); MediaSource mediaSource = new ProgressiveMediaSource.Factory(cachedDataSourceFactory) .createMediaSource(MediaItem.fromUri(Uri.parse(yourVideoUrl))); playerView.setPlayer(player); player.setPlayWhenReady(true); player.setMediaSource(mediaSource); player.prepare();
如果需要播放DASH流媒体,只需要把ProgressiveMediaSource.Factory替换为DashMediaSource.Factory即可,缓存逻辑完全通用。
注意事项
- 缓存逻辑和Glide完全一致:相同URL的视频第二次播放时会直接读取本地缓存,不会重复发起网络请求。
- 不要重复创建SimpleCache实例,否则会触发文件锁异常,导致缓存失效、播放崩溃。
- 如果需要实现视频预加载、秒开功能,可以使用
CacheWriter提前将视频片段写入缓存,后续播放时直接读取本地文件。 - 不需要为缓存申请任何存储权限,应用私有目录的读写在所有Android版本上都不受隐私政策限制。
内容的提问来源于stack exchange,提问作者StackOverflower

