You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何让MediaPlayer在应用被杀死后仍持续运行?使用Service实现方案

实现MediaPlayer后台持续播放的完整方案

我来帮你把这个实现补全并优化,让你的MediaPlayer就算在应用被杀死后也能稳稳在后台播放~你的思路是对的,用Service托管MediaPlayer,但要注意Android 8.0及以上的后台限制,普通后台Service很容易被系统回收,所以得做一些适配和完善。

1. 清单文件配置

除了注册Service,还要添加前台服务权限,并且针对Android 12+指定服务的前台类型,避免被系统限制:

<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />

<application ...>
    <service
        android:name=".MyService"
        android:enabled="true"
        android:exported="false" <!-- 避免被其他应用调用,更安全 -->
        android:foregroundServiceType="mediaPlayback" /> <!-- Android12+必需,明确服务用途 -->
</application>

2. 完善MyService类

你给出的代码只写了一部分,这里补全完整实现,包括前台通知、MediaPlayer的资源释放、Service重启策略,避免内存泄漏:

import android.app.Notification;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Build;
import android.os.IBinder;
import android.provider.Settings;

import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;

public class MyService extends Service {
    private MediaPlayer mediaPlayer;
    private static final int NOTIFICATION_ID = 1001;
    private static final String CHANNEL_ID = "MEDIA_PLAYBACK_CHANNEL";

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null; // 咱们不需要绑定服务,直接返回null就行
    }

    @Override
    public void onCreate() {
        super.onCreate();
        // Android8+必须创建通知渠道,否则通知弹不出来
        createNotificationChannel();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // 初始化MediaPlayer,避免重复创建
        if (mediaPlayer == null) {
            mediaPlayer = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
            mediaPlayer.setLooping(true);
            mediaPlayer.start();
        }

        // 启动前台服务,必须显示通知,不然Android8+会直接杀死服务
        startForeground(NOTIFICATION_ID, buildNotification());

        // 返回START_STICKY:如果服务被系统杀死,等资源空闲时会自动重启,但不会重新传Intent
        // 要是你需要重启时恢复播放进度这类状态,可以改用START_REDELIVER_INTENT,重启时会把之前的Intent传回来
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        // 一定要释放MediaPlayer!不然会占着音频资源还内存泄漏
        if (mediaPlayer != null) {
            mediaPlayer.stop();
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }

    // 创建通知渠道(Android8+必备)
    private void createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            NotificationChannel channel = new NotificationChannel(
                    CHANNEL_ID,
                    "媒体播放",
                    NotificationManager.IMPORTANCE_LOW // 设成低优先级,别打扰用户
            );
            NotificationManager manager = getSystemService(NotificationManager.class);
            if (manager != null) {
                manager.createNotificationChannel(channel);
            }
        }
    }

    // 构建前台通知,用户能看到后台在播放
    private Notification buildNotification() {
        // 点击通知可以跳回你的主Activity,按需修改Intent就行
        Intent intent = new Intent(this, MainActivity.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(
                this,
                0,
                intent,
                PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT
        );

        return new NotificationCompat.Builder(this, CHANNEL_ID)
                .setSmallIcon(R.drawable.ic_notification) // 替换成你自己的通知图标
                .setContentTitle("正在播放媒体")
                .setContentText("后台持续播放中")
                .setContentIntent(pendingIntent)
                .setPriority(NotificationCompat.PRIORITY_LOW)
                .build();
    }
}

3. 启动Service的正确姿势

在你的Activity或者其他组件里启动这个Service,注意Android版本差异:

Intent serviceIntent = new Intent(this, MyService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    startForegroundService(serviceIntent); // Android8+必须用这个方法启动前台服务
} else {
    startService(serviceIntent);
}

几个关键提醒

  • 前台服务是必须的:Android8.0之后,后台服务在应用退后台一段时间后会被系统强制回收,只有带通知的前台服务才能持续运行
  • 资源释放别忘onDestroy里一定要释放MediaPlayer,不然会造成内存泄漏,还可能导致其他应用无法使用音频
  • 重启策略选合适的START_STICKY适合简单的循环播放场景;如果需要保存播放进度、当前曲目这类状态,就用START_REDELIVER_INTENT,重启时能拿到之前的Intent,你可以在Intent里塞状态数据

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

火山引擎 最新活动