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

如何不调用ExoPlayer.prepare()预加载ProgressiveMediaSource视频

无需ExoPlayer实例实现视频预加载的方案

你遇到的核心问题是ProgressiveMediaSource.prepareSource()本身不会主动触发媒体数据下载——它仅完成MediaSource的初始化工作,必须依赖Player实例驱动数据加载。要绕开Player实现预加载,直接利用ExoPlayer的缓存机制主动拉取数据到缓存即可,具体实现如下:

实现思路

复用你已配置好的CacheDataSource.Factory,直接创建DataSource实例,手动读取媒体流数据。CacheDataSource会自动将读取到的内容写入你设置的SimpleCache中,以此达到预加载的效果。这种方式完全基于缓存组件完成,不需要创建ExoPlayer实例。

代码实现

1. 预加载工具方法(推荐用协程在后台执行)

import android.content.Context
import com.google.android.exoplayer2.upstream.CacheDataSource
import com.google.android.exoplayer2.upstream.DataSource
import com.google.android.exoplayer2.upstream.DefaultHttpDataSource
import com.google.android.exoplayer2.upstream.SimpleCache
import com.google.android.exoplayer2.util.Util
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.IOException
import java.io.InputStream
import java.net.URI

suspend fun preloadVideoToCache(
    context: Context,
    cache: SimpleCache,
    videoUri: String,
    preloadBytes: Long = 5 * 1024 * 1024 // 预加载前5MB,可按需调整
) = withContext(Dispatchers.IO) {
    val dataSourceFactory = CacheDataSource.Factory()
        .setCache(cache)
        .setUpstreamDataSourceFactory(
            DefaultHttpDataSource.Factory()
                .setUserAgent(Util.getUserAgent(context, "ExoplayerDemo"))
        )
        .setFlags(CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR)

    var dataSource: DataSource? = null
    var inputStream: InputStream? = null

    try {
        dataSource = dataSourceFactory.createDataSource()
        val dataSpec = DataSource.DataSpec(URI.create(videoUri).toUri())
        inputStream = dataSource.open(dataSpec)

        val buffer = ByteArray(8192)
        var totalRead = 0L
        var read: Int

        // 读取指定字节数的内容,直到完成或流结束
        while (totalRead < preloadBytes && inputStream.read(buffer).also { read = it } != -1) {
            totalRead += read
            // 无需处理读取到的数据,CacheDataSource会自动完成缓存
        }
    } catch (e: IOException) {
        // 处理加载异常,比如网络错误、资源不存在等
        e.printStackTrace()
    } finally {
        inputStream?.close()
        dataSource?.close()
    }
}

2. 调用预加载方法

在合适的时机(比如App启动、进入目标页面时)调用:

// 在Activity或ViewModel的后台逻辑中执行
lifecycleScope.launch {
    preloadVideoToCache(
        context = this@YourActivity,
        cache = SimpleMediaPlayer.simpleCache,
        videoUri = "https:xxxxxxx/Sending+Data+to+a+New+Activity+with+Intent+Extras.mp4"
    )
}

关键说明

  • 生效原理:CacheDataSource在读取网络数据时,会自动将内容写入你配置的SimpleCache,后续使用ExoPlayer播放该视频时,会优先从缓存读取,实现预加载效果。
  • 预加载量控制:通过preloadBytes参数可指定预加载的字节数,避免一次性加载整个视频占用过多存储和带宽。
  • 线程要求:必须在后台线程执行,否则会阻塞主线程导致ANR,示例中用协程Dispatchers.IO是最便捷的方式。
  • 异常处理:记得捕获IO异常,避免因网络错误等情况导致崩溃。

内容的提问来源于stack exchange,提问作者coderror

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 10:10:34