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

在MainActivity中创建访问配合AlarmManager的BroadcastReceiver的正确方法(Kotlin)

在Activity中创建并使用供AlarmManager调用的BroadcastReceiver的正确方式

现有代码核心问题

  • 构建PendingIntent时传入的是指向MainActivity的启动意图,并非广播意图,系统不会将其分发给广播接收器
  • Activity内部定义的匿名广播接收器未做动态注册,系统无法感知其存在
  • 独立广播接收器的onReceive方法默认会传入Context参数,可直接用该参数获取系统服务、启动Activity,不存在无Context可用的问题

推荐实现方式(独立广播接收器,适配后台触发场景)

这种方式不需要依赖Activity存活,就算APP退到后台也能正常接收闹钟触发事件,是定时类需求的首选方案。

步骤1:创建独立的广播接收器类

新建AlarmReceiver.kt文件,代码如下:

class AlarmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        context ?: return
        // 播放指定音频
        val mp = MediaPlayer.create(context, R.raw.song_title)
        mp.setVolume(1.0f, 1.0f)
        mp.start()
        
        // 直接用onReceive传入的context更新下一次闹钟
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val nextIntent = Intent(context, AlarmReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(
            context,
            0,
            nextIntent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
        // 示例:设置次日8点的下次闹钟
        val nextTriggerTime = Calendar.getInstance().apply {
            add(Calendar.DAY_OF_YEAR, 1)
            set(Calendar.HOUR_OF_DAY, 8)
            set(Calendar.MINUTE, 0)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }.timeInMillis
        alarmManager.setAndAllowWhileIdle(
            AlarmManager.RTC_WAKEUP,
            nextTriggerTime,
            pendingIntent
        )
    }
}

步骤2:在AndroidManifest.xml中注册接收器

在application标签内添加如下配置:

<receiver
    android:name=".AlarmReceiver"
    android:exported="false" />

步骤3:在MainActivity中设置闹钟

修正后的onCreate代码:

private lateinit var alarmManager: AlarmManager

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
    // 创建指向AlarmReceiver的广播意图
    val intent = Intent(this, AlarmReceiver::class.java)
    val pendingIntent = PendingIntent.getBroadcast(
        this,
        0,
        intent,
        // Android12+必须指定PendingIntent可变性,普通定时场景用IMMUTABLE即可
        PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
    )
    // 设置1分钟后触发
    val triggerTime = Calendar.getInstance().apply {
        add(Calendar.MINUTE, 1)
        set(Calendar.SECOND, 0)
        set(Calendar.MILLISECOND, 0)
    }.timeInMillis

    alarmManager.setAndAllowWhileIdle(
        AlarmManager.RTC_WAKEUP,
        triggerTime,
        pendingIntent
    )
}

可选实现方式(Activity内部动态注册,仅前台生效)

如果你的定时需求仅在APP前台运行时生效,可以选择将广播接收器写在Activity内部,注意必须完成动态注册和注销。
完整代码示例:

class MainActivity : AppCompatActivity() {
    private lateinit var alarmManager: AlarmManager
    // 自定义广播Action,用于匹配接收器
    private val ALARM_ACTION = "com.your_package_name.ALARM_TRIGGER"

    // 广播接收器作为类成员变量
    private val broadCastReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            if (intent?.action == ALARM_ACTION) {
                val mp = MediaPlayer.create(context, R.raw.song_title)
                mp.setVolume(1.0f, 1.0f)
                mp.start()
                // 可直接访问Activity内的alarmManager更新下次闹钟
            }
        }
    }

    override fun onResume() {
        super.onResume()
        // 动态注册广播接收器
        registerReceiver(broadCastReceiver, IntentFilter(ALARM_ACTION))
    }

    override fun onPause() {
        super.onPause()
        // 注销接收器,避免内存泄漏
        unregisterReceiver(broadCastReceiver)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        alarmManager = getSystemService(ALARM_SERVICE) as AlarmManager
        // 构建带自定义Action的广播意图
        val intent = Intent(ALARM_ACTION).apply {
            // 适配Android8.0+隐式广播限制,指定当前APP包名
            setPackage(packageName)
        }
        val pendingIntent = PendingIntent.getBroadcast(
            this,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        val triggerTime = Calendar.getInstance().apply {
            add(Calendar.MINUTE, 1)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
        }.timeInMillis

        alarmManager.setAndAllowWhileIdle(
            AlarmManager.RTC_WAKEUP,
            triggerTime,
            pendingIntent
        )
    }
}

注意事项

  • 若有多个不同的定时任务,创建PendingIntent时要使用不同的requestCode参数,否则会互相覆盖
  • Android 6.0+的低电耗模式下,setAndAllowWhileIdle方法每15分钟最多触发一次,若需要更高精度的定时,可申请忽略电池优化权限
  • 动态注册的广播接收器必须对应注销,否则会引发内存泄漏

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 07:45:03