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

API 31+下基于Media3实现每日后台预下载媒体资源的方案咨询

基于Media3实现健身媒体预缓存的最佳实践

针对健身应用的媒体预下载需求,结合Android后台限制(尤其是API 31+)和Media3的特性,推荐以下落地方案:

一、用WorkManager替代AlarmManager,精准控制触发时机

放弃手动用AlarmManager唤醒Worker,直接借助WorkManager的PeriodicWorkRequest调度每日预下载任务——它会自动适配系统后台调度规则,同时可配置严格的触发约束:

  • 要求设备处于充电状态
  • 要求设备联网(可选限制为WiFi)
  • 精准设置每日5点的触发时间

示例代码片段:

val constraints = Constraints.Builder()
    .setRequiresCharging(true)
    .setRequiredNetworkType(NetworkType.UNMETERED) // 可选:仅允许WiFi下下载
    .build()

val periodicWork = PeriodicWorkRequestBuilder<PreDownloadWorker>(1, TimeUnit.DAYS)
    .setInitialDelay(calculateDelayTo5AM(), TimeUnit.MILLISECONDS)
    .setConstraints(constraints)
    .build()

WorkManager.getInstance(context).enqueueUniquePeriodicWork(
    "daily_fitness_pre_download",
    ExistingPeriodicWorkPolicy.REPLACE,
    periodicWork
)

// 计算当前时间到次日5点的延迟时长
private fun calculateDelayTo5AM(): Long {
    val calendar = Calendar.getInstance().apply {
        set(Calendar.HOUR_OF_DAY, 5)
        set(Calendar.MINUTE, 0)
        set(Calendar.SECOND, 0)
    }
    if (calendar.timeInMillis <= System.currentTimeMillis()) {
        calendar.add(Calendar.DAY_OF_YEAR, 1)
    }
    return calendar.timeInMillis - System.currentTimeMillis()
}

二、在Worker内正确调用Media3 DownloadManager

在CoroutineWorker的doWork()方法中,先调用setForegroundAsync()将Worker置为前台状态(这是绕过API 31+后台启动限制的核心),然后直接使用Media3的DownloadManager.addDownload()调度下载——绝对不要调用DownloadService.sendAddDownload(),因为该方法会尝试后台启动前台服务,触发ForegroundServiceStartNotAllowedException。

同时为避免ANR,必须用协程异步处理批量下载:

class PreDownloadWorker(
    context: Context,
    params: WorkerParameters
) : CoroutineWorker(context, params) {

    override suspend fun doWork(): Result {
        // 创建前台通知,告知用户正在预下载健身内容
        val notification = NotificationCompat.Builder(applicationContext, DOWNLOAD_CHANNEL_ID)
            .setContentTitle("健身内容预下载")
            .setContentText("正在为您准备今日健身媒体")
            .setSmallIcon(R.drawable.ic_download)
            .build()

        setForegroundAsync(ForegroundInfo(DOWNLOAD_NOTIFICATION_ID, notification))

        val downloadManager = DownloadManager.getInstance(applicationContext)
        val downloadRequests = getDailyFitnessDownloadRequests() // 自定义方法,获取当日需预下载的媒体请求

        // 分批次异步添加下载请求,避免阻塞线程
        downloadRequests.chunked(10).forEach { chunk ->
            withContext(Dispatchers.IO) {
                chunk.forEach { request ->
                    downloadManager.addDownload(request)
                }
            }
            delay(500) // 批次间短暂延迟,降低系统负载
        }

        return Result.success()
    }

    // 自定义方法:生成当日需要预下载的DownloadRequest列表
    private fun getDailyFitnessDownloadRequests(): List<DownloadRequest> {
        // 根据健身流程逻辑,返回对应的视频/音频下载请求
        return mutableListOf()
    }

    companion object {
        private const val DOWNLOAD_CHANNEL_ID = "fitness_pre_download_channel"
        private const val DOWNLOAD_NOTIFICATION_ID = 1001
    }
}

三、Manifest配置要点

确保正确注册Media3的DownloadService,并声明必要权限:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<uses-permission android:name="android.permission.INTERNET" />

<application ...>
    <service
        android:name="androidx.media3.exoplayer.download.DownloadService"
        android:exported="false">
        <intent-filter>
            <action android:name="androidx.media3.exoplayer.download.DownloadService.ACTION_INITIALIZE" />
        </intent-filter>
    </service>
</application>

四、之前方案的问题根源

  • 方案1失败原因:API 31+禁止后台通过sendAddDownload()启动前台服务,而DownloadManager内部已封装前台服务的启动逻辑(会自动判断系统权限),直接调用addDownload()即可规避该问题。
  • 方案2的ANR问题:批量添加下载请求时在主线程同步执行,或Worker执行时间过长。通过分批次异步处理、添加延迟,可有效避免ANR。

额外优化建议

  • 给用户提供预下载开关,让用户自主选择是否开启该功能
  • 为预下载的媒体设置过期策略(比如7天后自动删除),避免占用过多存储
  • 通过DownloadManager.Listener监听下载状态,失败时结合WorkManager的重试机制自动重试

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 20:00:00