点击通知停止AlarmManager闹钟播放的实现求助
解决点击通知停止闹钟播放的问题
我明白你现在的困扰——在BroadcastReceiver里直接创建MediaPlayer播放闹钟,不仅生命周期不稳定,还没法通过点击通知来控制它停止。咱们一步步来解决这个问题:
核心问题分析
你当前的代码里,MediaPlayer是onReceive方法里的局部变量,当onReceive执行完毕后,这个MediaPlayer会被系统回收,而且你没法从其他组件(比如点击通知打开的AddNoteActivity)访问到它,自然没法停止播放。另外,BroadcastReceiver不适合做长时间的音频播放操作,应该用Service来管理音频播放。
解决方案步骤
1. 创建一个Foreground Service来管理MediaPlayer
这个Service负责播放和停止闹钟音频,因为Foreground Service优先级更高,不容易被系统杀死,而且能跨组件控制。
public class AlarmSoundService extends Service { private MediaPlayer mediaPlayer; @Override public void onCreate() { super.onCreate(); // 初始化MediaPlayer mediaPlayer = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI); mediaPlayer.setLooping(true); // 让闹钟循环播放,直到手动停止 } @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); if (action != null) { switch (action) { case "PLAY_ALARM": startForeground(101, createNotification()); // 前台服务必须显示通知 if (!mediaPlayer.isPlaying()) { mediaPlayer.start(); } break; case "STOP_ALARM": stopAlarm(); stopForeground(true); stopSelf(); break; } } return START_STICKY; } private Notification createNotification() { // 创建停止闹钟的PendingIntent Intent stopIntent = new Intent(this, AlarmSoundService.class); stopIntent.setAction("STOP_ALARM"); PendingIntent stopPendingIntent = PendingIntent.getService(this, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 构建通知 return new NotificationCompat.Builder(this, NotificationHelper.chanel1ID) .setContentTitle("闹钟响了") .setContentText("点击停止闹钟") .setSmallIcon(R.drawable.ic_notifications_black_24dp) .setContentIntent(stopPendingIntent) .setAutoCancel(true) .build(); } private void stopAlarm() { if (mediaPlayer != null && mediaPlayer.isPlaying()) { mediaPlayer.stop(); mediaPlayer.release(); mediaPlayer = null; } } @Override public void onDestroy() { super.onDestroy(); stopAlarm(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }
2. 修改MyAlarm BroadcastReceiver
现在Receiver不再直接播放音频,而是启动上面的Service:
public class MyAlarm extends BroadcastReceiver { private static final int NOTIFICATION_ID = 101; @Override public void onReceive(final Context context, Intent intent) { // 启动播放闹钟的Service Intent serviceIntent = new Intent(context, AlarmSoundService.class); serviceIntent.setAction("PLAY_ALARM"); serviceIntent.setData(intent.getData()); // 传递原有的Uri数据 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent); } else { context.startService(serviceIntent); } } }
3. 更新NotificationHelper(可选,保留跳转到AddNoteActivity的功能)
如果你希望点击通知既停止闹钟又打开AddNoteActivity,可以创建一个组合PendingIntent,先执行停止操作再打开Activity:
// 在NotificationHelper中修改getChannel1Notification方法 public NotificationCompat.Builder getChannel1Notification(Context context, Uri uri) { // 停止闹钟的Intent Intent stopIntent = new Intent(context, AlarmSoundService.class); stopIntent.setAction("STOP_ALARM"); PendingIntent stopPendingIntent = PendingIntent.getService(context, 0, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 打开AddNoteActivity的Intent Intent activityIntent = new Intent(context, AddNoteActivity.class); activityIntent.setData(uri); PendingIntent activityPendingIntent = PendingIntent.getActivity(context, 1, activityIntent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); // 组合两个Intent:先停止闹钟,再打开Activity Intent[] combinedIntents = {stopIntent, activityIntent}; PendingIntent combinedPendingIntent = PendingIntent.getActivities(context, 0, combinedIntents, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); return new NotificationCompat.Builder(getApplicationContext(), chanel1ID) .setContentTitle("闹钟响了") .setContentText("点击停止并打开笔记") .setSmallIcon(R.drawable.ic_notifications_black_24dp) .setContentIntent(combinedPendingIntent) .setAutoCancel(true); }
4. 声明权限和Service
在AndroidManifest.xml里添加必要的权限和组件声明:
<!-- Android 12及以上需要前台服务权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <!-- Android 13及以上需要通知权限 --> <uses-permission android:name="android.permission.POST_NOTIFICATIONS" /> <application ...> <service android:name=".AlarmSoundService" /> <receiver android:name=".MyAlarm" /> <!-- 你的其他组件声明 --> </application>
关键说明
- 使用Foreground Service是因为音频播放属于长时间操作,普通Service容易被系统回收,Foreground Service能保证播放稳定。
- 通过给Service发送带Action的Intent来控制播放和停止,这样点击通知时就能触发停止操作。
- 注意PendingIntent的Flag,Android 12+需要添加
FLAG_IMMUTABLE或者FLAG_MUTABLE,避免兼容性问题。
这样修改后,点击通知就能停止闹钟播放了,而且音频播放的生命周期也更稳定。
内容的提问来源于stack exchange,提问作者newbieHere
相关产品推荐
相关产品推荐

