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

AlarmManager通知点击后铃声不停止及振动失效问题求助

日历应用闹钟功能问题求助

我正在开发一款日历应用,已实现支持自定义日期时间的闹钟功能,闹钟可正常触发,但存在两个问题:

  • 推送通知弹出后,点击通知进入应用时,铃声仍持续播放直至退出应用,目前仅能通过设置10秒延迟停止铃声,需求是点击通知时立即停止铃声;
  • 振动功能无法正常工作,希望能解决该问题。

以下是我的AlarmReceiver类代码:

public class AlarmReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
        vibrator.vibrate(VibrationEffect.DEFAULT_AMPLITUDE);

        String event = intent.getStringExtra("title");
        String comment = intent.getStringExtra("comment");
        Intent activityIntent = new Intent(context, MainActivity.class);

        PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, activityIntent, 0);

        String text = "Reminder for the Event: " + "\n" + event + "\n" + "Comments: " + "\n" + comment;
        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "myandroid")
                .setSmallIcon(R.drawable.alarm)
                .setContentTitle(event)
                .setContentText(text)
                .setAutoCancel(true)
                .setStyle(new NotificationCompat.BigTextStyle()
                        .bigText(text))
                .setContentIntent(pendingIntent)
                .setDeleteIntent(pendingIntent)
                .setDefaults(NotificationCompat.DEFAULT_ALL)
                .setPriority(NotificationCompat.PRIORITY_HIGH);

        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(context);
        notificationManagerCompat.notify(123, builder.build());

        Notification notification1 = builder.build();
        notification1.flags |= Notification.FLAG_AUTO_CANCEL;

        Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
        Ringtone r = RingtoneManager.getRingtone(context, notification);
        r.play();

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (r.isPlaying())
                    r.stop();
            }
        }, 1000*10 );
    }
}

问题1:点击通知立即停止铃声的解决方案

当前问题在于Ringtone实例仅存在于AlarmReceiver的onReceive方法中,点击通知打开MainActivity时无法直接访问并停止它。推荐两种实现方式:

方式1:全局静态变量管理铃声实例

修改AlarmReceiver,将Ringtone设为静态变量,然后在MainActivity的生命周期方法中停止播放:

public class AlarmReceiver extends BroadcastReceiver {
    public static Ringtone sAlarmRingtone; // 静态变量保存铃声实例

    @Override
    public void onReceive(Context context, Intent intent) {
        // ... 原有振动、通知代码不变 ...

        Uri notificationUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
        sAlarmRingtone = RingtoneManager.getRingtone(context, notificationUri);
        sAlarmRingtone.play();

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (sAlarmRingtone != null && sAlarmRingtone.isPlaying()) {
                    sAlarmRingtone.stop();
                    sAlarmRingtone = null;
                }
            }
        }, 1000*10 );
    }
}

在MainActivity的onResume方法中停止铃声:

@Override
protected void onResume() {
    super.onResume();
    if (AlarmReceiver.sAlarmRingtone != null && AlarmReceiver.sAlarmRingtone.isPlaying()) {
        AlarmReceiver.sAlarmRingtone.stop();
        AlarmReceiver.sAlarmRingtone = null; // 释放资源
    }
}

方式2:使用Service管理铃声播放(更稳定)

由于BroadcastReceiver生命周期极短,系统可能提前回收其资源,使用Service管理播放更可靠:

  1. 创建AlarmSoundService类:
public class AlarmSoundService extends Service {
    private Ringtone mRingtone;

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        Uri notificationUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
        mRingtone = RingtoneManager.getRingtone(this, notificationUri);
        if (!mRingtone.isPlaying()) {
            mRingtone.play();
        }
        // 设置10秒后自动停止
        new Handler().postDelayed(() -> {
            stopSelf();
        }, 1000*10);
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mRingtone != null && mRingtone.isPlaying()) {
            mRingtone.stop();
        }
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
  1. 在AlarmReceiver的onReceive中启动Service替代直接播放:
// 替换原有Ringtone播放代码
Intent serviceIntent = new Intent(context, AlarmSoundService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    context.startForegroundService(serviceIntent);
} else {
    context.startService(serviceIntent);
}
  1. 在MainActivity的onResume中停止Service:
@Override
protected void onResume() {
    super.onResume();
    Intent serviceIntent = new Intent(this, AlarmSoundService.class);
    stopService(serviceIntent);
}
  1. 在AndroidManifest.xml中注册Service:
<service android:name=".AlarmSoundService" />

问题2:振动功能修复方案

当前振动代码存在版本兼容问题且未指定振动时长,同时缺少必要权限,修复步骤如下:

  1. 添加振动权限:在AndroidManifest.xml中添加:
<uses-permission android:name="android.permission.VIBRATE" />
  1. 兼容多版本的振动代码:替换原有振动代码为:
Vibrator vibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
if (vibrator != null) {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
        // API 26+,创建单次振动,时长500毫秒
        vibrator.vibrate(VibrationEffect.createOneShot(500, VibrationEffect.DEFAULT_AMPLITUDE));
    } else {
        // 低版本直接指定振动时长
        vibrator.vibrate(500);
    }
}
  1. 注意通知默认振动冲突:你设置了setDefaults(NotificationCompat.DEFAULT_ALL),该属性会让通知自带振动效果,若想完全自定义振动逻辑,可移除该设置,避免重复振动。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 23:05:17