You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 04:02:36