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

使用WorkManager实现Android后台音频播放遇问题求助

问题核心原因

你的方案存在两个关键问题:

  1. WorkManager Worker的生命周期限制:doWork()是同步执行方法,调用audioPlayer.start()后立刻返回Result.success(),Worker的生命周期随即结束,系统会回收该Worker占用的进程资源,导致MediaPlayer失去宿主无法继续播放。
  2. Android后台进程限制:API 26(Android 8.0)以后,系统对普通后台任务有严格的资源限制,未持有前台优先级的进程会在短时间内被系统杀死,这就是你看到后台播放7秒就停止的直接原因。
正确解决方案:使用前台服务播放音频

音频后台播放属于需要持续占用系统资源的场景,必须使用前台服务(Foreground Service),它拥有更高的进程优先级,且强制要求显示通知(符合Android后台规范),不会被系统轻易回收。如果一定要通过WorkManager触发播放,只需让Worker启动前台服务即可。

步骤1:添加权限与服务注册

在AndroidManifest.xml中添加权限和服务声明:

<!-- 前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<!-- API 34+ 专用媒体播放前台服务权限 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
<!-- API 33+ 通知权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<!-- 注册音频播放前台服务 -->
<service
    android:name=".AudioForegroundService"
    android:foregroundServiceType="mediaPlayback" /> <!-- API 31+ 推荐设置服务类型 -->

步骤2:实现前台服务类

创建AudioForegroundService.kt,负责音频播放和前台通知管理:

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.media.MediaPlayer
import android.os.Build
import android.os.IBinder

class AudioForegroundService : Service() {
    private var mediaPlayer: MediaPlayer? = null
    private val CHANNEL_ID = "AUDIO_PLAYBACK_CHANNEL"

    override fun onCreate() {
        super.onCreate()
        // 创建通知渠道(API 26+ 必需)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "音频播放",
                NotificationManager.IMPORTANCE_LOW
            )
            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(channel)
        }
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 构建前台通知
        val notification = Notification.Builder(this, CHANNEL_ID)
            .setContentTitle("音频播放中")
            .setContentText("正在后台播放音频")
            .setSmallIcon(R.drawable.ic_audio_icon) // 替换为你的应用图标
            .setPriority(Notification.PRIORITY_LOW)
            .build()

        // 启动前台服务
        startForeground(1001, notification)

        // 初始化并启动音频播放
        val filePath = "/data/user/0/me.soft.audioserver/app_Audio_Directory/TheAudioFile.mp3"
        mediaPlayer = MediaPlayer().apply {
            try {
                setDataSource(filePath)
                prepare()
                start()
                // 播放完成后自动停止服务
                setOnCompletionListener { stopSelf() }
            } catch (e: Exception) {
                e.printStackTrace()
                stopSelf()
            }
        }

        return START_STICKY
    }

    override fun onDestroy() {
        super.onDestroy()
        // 释放MediaPlayer资源
        mediaPlayer?.release()
        mediaPlayer = null
    }

    override fun onBind(intent: Intent?): IBinder? = null
}

步骤3:修改Worker类

让Worker负责启动前台服务,不再直接处理音频播放:

import android.content.Intent
import android.os.Build
import androidx.work.Worker
import androidx.work.WorkerParameters

class AudioWorker(context: Context, workerParams: WorkerParameters) : Worker(context, workerParams) {
    override fun doWork(): Result {
        val intent = Intent(applicationContext, AudioForegroundService::class.java)
        // 启动前台服务(API 26+ 必须用startForegroundService)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            applicationContext.startForegroundService(intent)
        } else {
            applicationContext.startService(intent)
        }
        return Result.success()
    }
}

步骤4:处理动态权限(API 33+)

在主Activity中添加通知权限的动态申请(用户同意后才能显示前台通知):

import android.Manifest
import android.content.pm.PackageManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {
    private val requestNotificationPermissionLauncher = registerForActivityResult(
        ActivityResultContracts.RequestPermission()
    ) { isGranted ->
        if (isGranted) {
            // 权限已同意,可正常触发播放
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        // 检查并申请通知权限(API 33+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
                requestNotificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
            }
        }

        // 播放按钮点击事件(保持原有逻辑即可)
        playBtn.setOnClickListener {
            val playWorkRequest = OneTimeWorkRequestBuilder<AudioWorker>().build()
            val wrkMgr = WorkManager.getInstance(applicationContext)
            wrkMgr.enqueue(playWorkRequest)

            wrkMgr.getWorkInfoByIdLiveData(playWorkRequest.id)
                .observe(this) { info ->
                    info?.let {
                        if (it.state.isFinished) {
                            println("音频播放任务已启动")
                        }
                    }
                }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 15:55:19