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

Android:AlarmManager触发后如何显示弹窗并取消闹钟?

好的,我来帮你实现这个带取消功能的闹钟弹窗!你现在的代码已经完成了闹钟的设置和触发时的铃声播放,接下来只需要调整触发逻辑,用一个透明主题的Activity来承载弹窗(因为BroadcastReceiver里不能直接创建Dialog,它没有UI上下文),这样就能实现点击取消按钮关闭闹钟的功能了。

具体实现步骤

1. 配置透明主题的Activity

首先在AndroidManifest.xml里注册一个专门用来显示弹窗的Activity,给它设置透明主题:

<activity
    android:name=".AlarmDialogActivity"
    android:theme="@style/TransparentActivityTheme"
    android:excludeFromRecents="true"
    android:launchMode="singleInstance">
</activity>

然后在res/values/styles.xml中添加这个透明主题:

<style name="TransparentActivityTheme" parent="Theme.AppCompat.Light.NoActionBar">
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowIsTranslucent">true</item>
    <item name="android:windowNoTitle">true</item>
    <item name="android:windowAnimationStyle">@null</item>
</style>

2. 编写弹窗Activity的核心逻辑

创建AlarmDialogActivity.java,这里负责显示弹窗、播放铃声,以及处理取消闹钟的逻辑:

public class AlarmDialogActivity extends AppCompatActivity {
    private MediaPlayer mediaPlayer;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // 初始化并循环播放铃声
        mediaPlayer = MediaPlayer.create(this, Settings.System.DEFAULT_RINGTONE_URI);
        mediaPlayer.setLooping(true);
        mediaPlayer.start();

        // 显示带取消按钮的弹窗
        new AlertDialog.Builder(this)
                .setTitle("闹钟提醒")
                .setMessage("该起床啦!点击取消关闭闹钟")
                .setPositiveButton("取消闹钟", (dialog, which) -> {
                    // 停止并释放铃声资源
                    if (mediaPlayer != null && mediaPlayer.isPlaying()) {
                        mediaPlayer.stop();
                        mediaPlayer.release();
                    }
                    // 根据传入的Uri取消对应的闹钟
                    cancelAlarm(getIntent().getData());
                    // 关闭弹窗Activity
                    finish();
                })
                .setCancelable(false) // 禁止点击外部关闭弹窗,必须操作按钮
                .show();
    }

    private void cancelAlarm(Uri alarmUri) {
        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
        Intent intent = new Intent(this, MyAlarm.class);
        intent.setData(alarmUri);
        // 注意:这里的PendingIntent参数必须和设置闹钟时完全一致,才能正确匹配并取消
        int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0;
        PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, flags);
        
        if (pendingIntent != null) {
            alarmManager.cancel(pendingIntent);
            pendingIntent.cancel();
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // 确保退出时释放MediaPlayer,避免内存泄漏
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
    }
}

3. 修改广播接收器的触发逻辑

原来的MyAlarm广播只播放铃声,现在改成启动上面的弹窗Activity,同时把闹钟的Uri传过去,方便后续取消:

public class MyAlarm extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // 启动弹窗Activity,必须添加FLAG_ACTIVITY_NEW_TASK标志(广播中启动Activity的要求)
        Intent dialogIntent = new Intent(context, AlarmDialogActivity.class);
        dialogIntent.setData(intent.getData());
        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(dialogIntent);
    }
}

4. 优化设置闹钟的代码(可选但重要)

调整setAlarm方法中的PendingIntent标志,适配Android 12及以上版本的要求:

public void setAlarm(long timeInMillis){
    if(Build.VERSION.SDK_INT >= 23){
        // 修正Calendar的设置顺序(年、月、日、时、分、秒)
        mCalendar.set(Calendar.YEAR, mCalendar.get(Calendar.YEAR));
        mCalendar.set(Calendar.MONTH, mCalendar.get(Calendar.MONTH));
        mCalendar.set(Calendar.DAY_OF_YEAR, mCalendar.get(Calendar.DAY_OF_YEAR));
        mCalendar.set(Calendar.HOUR_OF_DAY, mCalendar.get(Calendar.HOUR_OF_DAY));
        mCalendar.set(Calendar.MINUTE, mCalendar.get(Calendar.MINUTE));
        mCalendar.set(Calendar.SECOND, 0); // 加上秒数,确保触发时间精准
    }
    final AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
    Intent intent = new Intent(this, MyAlarm.class);
    intent.setData(currentUri);
    // 根据Android版本选择合适的PendingIntent标志
    int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S ? PendingIntent.FLAG_IMMUTABLE : 0;
    final PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, flags);
    alarmManager.setExact(AlarmManager.RTC, timeInMillis, pendingIntent);
}

几个关键注意点

  • PendingIntent匹配规则:取消闹钟时,必须使用和设置时完全相同的Intent(包括Data、Action等)以及相同的requestCode,否则无法找到对应的闹钟并取消。
  • 权限适配:Android 12及以上版本需要申请SCHEDULE_EXACT_ALARM权限,否则setExact方法可能无法正常工作。
  • 资源释放:一定要在Activity销毁时释放MediaPlayer,避免内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:49:51