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

Android:setExactAndAllowWhileIdle在Idle模式下无法触发通知的解决咨询

问题描述

尝试使用AlarmManager触发通知,但设备进入Idle/Doze模式后,通知无法弹出,仅在进入应用后才会显示。

Activity 代码

val intent = Intent(applicationContext, AlarmReceiver::class.java)
intent.putExtra(TITLE_EXTRA, "title")
intent.putExtra(MESSAGE_EXTRA, "adb shell dumpsys deviceidle step\n")

val pendingIntent = PendingIntent.getBroadcast(
    applicationContext,
    NOTIFICATION_ID,
    intent,
    PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
)

alarmManager.setExactAndAllowWhileIdle(
    AlarmManager.RTC_WAKEUP,
    System.currentTimeMillis() + 2 * 60000,
    pendingIntent
)

AlarmReceiver 代码

class AlarmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(intent.getStringExtra(TITLE_EXTRA))
            .setContentText(intent.getStringExtra(MESSAGE_EXTRA))
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build()

        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(NOTIFICATION_ID, builder)
    }
}

已添加的权限

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

解决方法

1. 补全Android 8.0+通知通道配置

Android 8.0及以上系统要求必须创建通知通道,且高优先级通知需要将通道重要性设为IMPORTANCE_HIGH,否则Doze模式下通知会被系统抑制。在应用启动阶段(如Application类或MainActivity的onCreate)添加通道创建代码:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
    val channel = NotificationChannel(
        CHANNEL_ID,
        "高优先级通知通道",
        NotificationManager.IMPORTANCE_HIGH
    ).apply {
        description = "用于Doze模式下的紧急通知"
        enableVibration(true)
        setShowBadge(true)
        setSound(null, null) // 可自定义提示音,或用DEFAULT_SOUND
    }
    val notificationManager = getSystemService(NotificationManager::class.java)
    notificationManager.createNotificationChannel(channel)
}

2. 保证BroadcastReceiver执行时的CPU唤醒

Doze模式下系统会限制CPU唤醒,BroadcastReceiver的onReceive可能因CPU休眠无法完成通知显示。可以手动获取唤醒锁确保任务完成:

class AlarmReceiver : BroadcastReceiver() {
    private var wakeLock: PowerManager.WakeLock? = null

    override fun onReceive(context: Context, intent: Intent) {
        // 获取唤醒锁,持有10秒足够完成通知显示
        val powerManager = context.getSystemService(Context.POWER_SERVICE) as PowerManager
        wakeLock = powerManager.newWakeLock(
            PowerManager.PARTIAL_WAKE_LOCK or PowerManager.ACQUIRE_CAUSES_WAKEUP,
            "YourApp:AlarmWakeLock"
        )
        wakeLock?.acquire(10 * 1000)

        // 原有通知逻辑,添加DEFAULT_ALL确保提示音、震动生效
        val builder = NotificationCompat.Builder(context, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(intent.getStringExtra(TITLE_EXTRA))
            .setContentText(intent.getStringExtra(MESSAGE_EXTRA))
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .setDefaults(NotificationCompat.DEFAULT_ALL)
            .build()

        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(NOTIFICATION_ID, builder)

        // 释放唤醒锁
        wakeLock?.release()
    }
}

同时在Manifest中添加唤醒锁权限:

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

3. 动态申请SCHEDULE_EXACT_ALARM权限(Android 12+)

Android 12(API 31)及以上,仅在Manifest声明SCHEDULE_EXACT_ALARM权限不够,需要动态检查并请求:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
    val alarmManager = getSystemService(AlarmManager::class.java)
    if (!alarmManager.canScheduleExactAlarms()) {
        startActivity(Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM))
    }
}

4. 改用WorkManager(推荐长期稳定任务)

Google推荐使用WorkManager处理Doze模式下的调度任务,它会自动适配系统休眠策略:

  • 定义Worker类:
class NotificationWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        val title = inputData.getString(TITLE_EXTRA)
        val message = inputData.getString(MESSAGE_EXTRA)

        val builder = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setContentTitle(title)
            .setContentText(message)
            .setPriority(NotificationCompat.PRIORITY_HIGH)
            .build()

        val notificationManager =
            applicationContext.getSystemService(NotificationManager::class.java)
        notificationManager.notify(NOTIFICATION_ID, builder)

        return Result.success()
    }
}
  • 调度任务:
val data = Data.Builder()
    .putString(TITLE_EXTRA, "title")
    .putString(MESSAGE_EXTRA, "adb shell dumpsys deviceidle step\n")
    .build()

val workRequest = OneTimeWorkRequestBuilder<NotificationWorker>()
    .setInitialDelay(2, TimeUnit.MINUTES)
    .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
    .setInputData(data)
    .build()

WorkManager.getInstance(applicationContext).enqueue(workRequest)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 07:15:36