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

Android Kotlin定时通知服务实现方案及代码示例请求

Android 精准定时通知实现方案(Kotlin)

普通后台Service在App进程被杀死后会停止工作,要实现App关闭/关机重启后仍能触发定时通知,需要结合AlarmManager(系统级定时触发)、BroadcastReceiver(接收触发事件)和开机广播接收器(重启后恢复定时),以下是完整实现代码:

1. AndroidManifest.xml 配置

添加必要权限并注册组件:

<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" /> <!-- 可选,防止触发时设备休眠 -->

<application ...>
    <!-- 开机广播接收器 -->
    <receiver
        android:name=".BootCompletedReceiver"
        android:enabled="true"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
            <action android:name="android.intent.action.QUICKBOOT_POWERON" /> <!-- 适配部分机型 -->
        </intent-filter>
    </receiver>

    <!-- 定时通知广播接收器 -->
    <receiver android:name=".NotificationReceiver" />

    <!-- 前台Service(若需后台执行额外任务) -->
    <service
        android:name=".NotificationForegroundService"
        android:foregroundServiceType="dataSync" />
</application>

2. 开机广播接收器(BootCompletedReceiver.kt)

手机开机后重新设置所有定时任务:

class BootCompletedReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (Intent.ACTION_BOOT_COMPLETED == intent.action ||
            "android.intent.action.QUICKBOOT_POWERON" == intent.action) {
            // 重新设置所有需要的定时通知
            AlarmScheduler.scheduleAlarm(context, 15, 0) // 15:00
            AlarmScheduler.scheduleAlarm(context, 17, 30) // 17:30
        }
    }
}

3. 定时通知广播接收器(NotificationReceiver.kt)

接收AlarmManager触发的事件,发送通知(或启动前台Service):

class NotificationReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // 发送通知
        showNotification(context)

        // 如果需要执行耗时操作,启动前台Service
        // val serviceIntent = Intent(context, NotificationForegroundService::class.java)
        // ContextCompat.startForegroundService(context, serviceIntent)
    }

    private fun showNotification(context: Context) {
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

        // Android 8.0+ 通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "TIMER_NOTIFICATION_CHANNEL",
                "定时通知",
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                description = "用于接收定时触发的通知"
            }
            notificationManager.createNotificationChannel(channel)
        }

        val notification = NotificationCompat.Builder(context, "TIMER_NOTIFICATION_CHANNEL")
            .setSmallIcon(R.drawable.ic_notification) // 替换为你的通知图标
            .setContentTitle("定时通知")
            .setContentText("到点啦!")
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .setAutoCancel(true)
            .build()

        notificationManager.notify(System.currentTimeMillis().toInt(), notification)
    }
}

4. 前台Service(可选,NotificationForegroundService.kt)

若需要在后台执行耗时任务,使用前台Service避免被系统杀死:

class NotificationForegroundService : Service() {
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        // 创建前台通知
        val notification = NotificationCompat.Builder(this, "TIMER_NOTIFICATION_CHANNEL")
            .setSmallIcon(R.drawable.ic_notification)
            .setContentTitle("后台任务执行中")
            .setContentText("正在处理定时任务")
            .setPriority(NotificationCompat.PRIORITY_LOW)
            .build()

        startForeground(1, notification)

        // 执行你的耗时任务,比如数据同步等
        // doWork()

        // 任务完成后停止前台服务
        stopForeground(STOP_FOREGROUND_REMOVE)
        stopSelf()

        return START_NOT_STICKY
    }

    override fun onBind(intent: Intent): IBinder? {
        return null
    }
}

5. 闹钟调度工具类(AlarmScheduler.kt)

封装AlarmManager的定时逻辑,适配不同Android版本:

object AlarmScheduler {
    fun scheduleAlarm(context: Context, hour: Int, minute: Int) {
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val intent = Intent(context, NotificationReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(
            context,
            getUniqueRequestCode(hour, minute), // 每个定时任务用唯一的请求码
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        // 设置触发时间(当天的指定时分)
        val calendar = Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, hour)
            set(Calendar.MINUTE, minute)
            set(Calendar.SECOND, 0)
            set(Calendar.MILLISECOND, 0)
            // 如果当前时间已经过了指定时间,设置为第二天的同一时间
            if (timeInMillis < System.currentTimeMillis()) {
                add(Calendar.DAY_OF_MONTH, 1)
            }
        }

        // 适配Android版本,使用精准触发的API
        when {
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    calendar.timeInMillis,
                    pendingIntent
                )
            }
            Build.VERSION.SDK_INT >= Build.VERSION_CODES.M -> {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    calendar.timeInMillis,
                    pendingIntent
                )
            }
            else -> {
                alarmManager.setExact(
                    AlarmManager.RTC_WAKEUP,
                    calendar.timeInMillis,
                    pendingIntent
                )
            }
        }
    }

    // 生成唯一的请求码,避免不同定时任务的PendingIntent冲突
    private fun getUniqueRequestCode(hour: Int, minute: Int): Int {
        return hour * 100 + minute
    }
}

6. 启动方式

在App首次启动时(比如MainActivity的onCreate方法)调用闹钟设置:

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

        // 请求通知权限(Android 13+)
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
            if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
                ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 1001)
            }
        }

        // 设置定时通知
        AlarmScheduler.scheduleAlarm(this, 15, 0)
        AlarmScheduler.scheduleAlarm(this, 17, 30)
    }
}

注意事项

  • Doze模式适配:使用setExactAndAllowWhileIdle可以让闹钟在Doze模式下也能触发,但频繁触发可能会被系统限制,尽量避免短间隔的定时任务。
  • 电池优化:部分厂商的电池优化会影响AlarmManager的触发,建议引导用户将App加入电池白名单。
  • 请求码唯一性:每个定时任务的PendingIntent请求码必须唯一,否则会覆盖之前的任务。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:15:32