ExoPlayer中Cache.getCachedLength与Downloader下载字节数为何不一致?
问题原因及解决方案
核心原因分析
- 下载数据未完全刷入磁盘:Downloader回调里的
bytesDownloaded是内存中统计的已接收字节数,但ExoPlayer的缓存是异步写入磁盘的。你取消下载后立刻调用getCachedLength,此时缓存还没完成磁盘写入,读取到的只是已写入的部分数据。 - 缓存分片存储机制:ExoPlayer的缓存按分片(chunk)存储,
getCachedLength只统计已完成写入的完整分片长度,而bytesDownloaded包含了正在下载的不完整分片数据。如果PRE_CACHE_SIZE刚好卡在某个分片中间,取消下载时这个不完整分片不会被计入缓存统计。 - URI参数不匹配:你传入
getCachedLength的URI可能和Downloader实际请求的原始URI不一致。比如mediaItem.localConfiguration?.uri是本地URI或重定向后的URI,和下载器用的远程URI不匹配,导致找不到对应缓存数据。 - 缓存范围参数限制:调用
getCachedLength(uri, 0, PRE_CACHE_SIZE)时,第三个参数是指定检查的最大范围长度。如果缓存分片的起始位置不在0到PRE_CACHE_SIZE范围内,或者缓存的是超出该范围的分片,统计结果就会偏小。
验证与修复方案
- 等待缓存写入完成:取消下载后不要立即调用
getCachedLength,可以加短暂延迟,或者通过CacheListener监听写入完成事件,再进行统计。示例代码:downloader.download { _, bytesDownloaded, _ -> Log.w(TAG, "bytesDownloaded: $bytesDownloaded") if (bytesDownloaded >= PRE_CACHE_SIZE) { downloader.cancel() // 用协程延迟等待缓存写入 delay(500) val cachedLength = cache.getCachedLength(mediaItem.localConfiguration?.uri.toString(), 0, PRE_CACHE_SIZE) Log.w(TAG, "cachedLength after wait: $cachedLength") } } - 使用正确的缓存Key:下载器实际用的缓存Key是基于请求URI和参数生成的,直接用
Downloader.getCacheKey(mediaItem)获取正确Key,传入getCachedLength:val cacheKey = downloader.getCacheKey(mediaItem) val cachedLength = cache.getCachedLength(cacheKey, 0, PRE_CACHE_SIZE) - 检查缓存文件实际大小:找到ExoPlayer的缓存目录,查看对应视频的缓存文件总大小,对比
bytesDownloaded和getCachedLength的数值,确认是统计逻辑还是写入问题。 - 改用
getCachedBytes统计总缓存字节:getCachedLength统计的是连续可播放的缓存长度,getCachedBytes统计的是所有已缓存的字节数,更贴近bytesDownloaded的统计逻辑:val totalCachedBytes = cache.getCachedBytes(cacheKey) Log.w(TAG, "totalCachedBytes: $totalCachedBytes")
内容的提问来源于stack exchange,提问作者Fikri Haikal
相关产品推荐
相关产品推荐

