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

Android开发:如何让AlarmManager触发的弹窗在应用未激活或未运行时仍能显示?

Android开发:如何让AlarmManager触发的弹窗在应用未激活或未运行时仍能显示?

看起来你已经搭好了基础的定时弹窗框架,但遇到了「应用在后台/锁屏时弹窗不显示」的问题——这其实是Android系统为了优化体验和性能,对后台组件启动、窗口显示做了严格限制导致的。下面我会结合你的代码,给出针对性的解决方案:

一、先搞定核心权限与Manifest配置

要在其他应用之上、甚至锁屏状态下显示弹窗,必须先获取必要权限并配置Activity属性:

  1. 添加权限声明
    在AndroidManifest.xml里加入以下权限:
<!-- 允许在其他应用窗口之上显示内容 -->
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<!-- 唤醒设备屏幕 -->
<uses-permission android:name="android.permission.WAKE_LOCK" />
<!-- Android 10+ 全屏Intent需要的权限 -->
<uses-permission android:name="android.permission.USE_FULL_SCREEN_INTENT" />
  1. 配置TransparentAlertActivity的Manifest属性
    给你的透明Activity加上这些属性,确保它能在锁屏、后台场景下被唤起:
<activity
    android:name=".TransparentAlertActivity"
    android:theme="@style/Theme.Transparent"
    <!-- 允许在锁屏显示 -->
    android:showOnLockScreen="true"
    <!-- 自动唤醒屏幕 -->
    android:turnScreenOn="true"
    <!-- 不在最近任务列表显示 -->
    android:excludeFromRecents="true"
    <!-- 单实例启动,避免重复创建 -->
    android:launchMode="singleInstance" />

二、修改TransparentAlertActivity,确保弹窗能强制显示

在Activity的onCreate方法里添加窗口Flag,强制让它突破锁屏和后台限制:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    
    // 添加关键窗口Flag,确保在锁屏、后台时正常显示
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
            | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
            | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
            | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD); // 可选:自动解锁键盘锁
    
    setContentView(R.layout.activity_transparent_alert);
    // 你的原有代码...
    viewModel = new ViewModelProvider(this).get(MedicationListViewModel.class);
    isActive();
    dialog();
}

三、适配Android 10+的后台启动限制

从Android 10(API 29)开始,系统禁止后台直接启动Activity,这时候我们需要用「全屏Intent+通知」的方案,这也是官方推荐的闹钟类应用做法:

  1. 先创建通知渠道(Android 8.0+必备)
    在你的Application类或者启动页的onCreate里添加:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    NotificationChannel channel = new NotificationChannel(
            "MED_ALARM_CHANNEL", 
            "服药提醒", 
            NotificationManager.IMPORTANCE_HIGH
    );
    channel.setDescription("定时服药提醒通知");
    NotificationManager notificationManager = getSystemService(NotificationManager.class);
    notificationManager.createNotificationChannel(channel);
}
  1. 修改BroadcastReceiver的逻辑
    把原来直接启动Activity的代码,改成适配高版本系统的逻辑:
public class ScheduledReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Intent scheduledIntent = new Intent(context, TransparentAlertActivity.class);
        scheduledIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // Android 10+ 使用全屏Intent触发弹窗
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
            if (notificationManager != null) {
                PendingIntent pendingIntent = PendingIntent.getActivity(
                        context, 
                        0, 
                        scheduledIntent, 
                        PendingIntent.FLAG_IMMUTABLE
                );

                Notification notification = new NotificationCompat.Builder(context, "MED_ALARM_CHANNEL")
                        .setSmallIcon(R.drawable.ic_your_notification_icon) // 替换成你的通知图标
                        .setContentTitle("服药提醒")
                        .setContentText("该吃药了!")
                        .setPriority(NotificationCompat.PRIORITY_HIGH)
                        .setFullScreenIntent(pendingIntent, true) // 关键:全屏Intent
                        .build();

                notificationManager.notify(1001, notification);
            }
        } else {
            // 低版本系统直接启动Activity
            context.startActivity(scheduledIntent);
        }
    }
}

四、引导用户开启SYSTEM_ALERT_WINDOW权限

这个权限不能通过普通的权限申请流程获取,需要引导用户到系统设置页面开启:

// 在你的主Activity里添加检查逻辑,比如启动时
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {
    Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION,
            Uri.parse("package:" + getPackageName()));
    startActivityForResult(intent, 100);
}

最后补充几个注意点

  • 测试时一定要把应用退到后台或者锁屏,模拟真实场景;
  • PendingIntent.FLAG_IMMUTABLE是Android 12+推荐的,如果你要兼容更低版本,可以根据SDK版本切换FLAG_IMMUTABLE或FLAG_UPDATE_CURRENT;
  • 如果你发现弹窗还是不显示,检查系统的「电池优化」设置,把你的应用加入白名单,避免AlarmManager被系统休眠。

备注:内容来源于stack exchange,提问作者Csaba Cube

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.23 10:37:50