You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android应用后台定时通知问题:ArrayList时间匹配触发失效

解决后台定时触发通知的问题

你说得完全对——把时间匹配和通知逻辑放在onCreate()里,确实只有应用启动的时候才会触发检查,后台或者退出后根本不会运行。要实现后台也能触发通知,得用Android专门的后台定时任务机制,我给你两个靠谱的方案,按需选就行:

方案一:用WorkManager(推荐,适配性强)

WorkManager是Google推荐的后台任务调度工具,能自动适配Android 8.0+的后台限制,不用太担心系统杀进程的问题。适合你的场景是:时间列表可能动态变化,需要定期检查当前时间是否匹配。

步骤1:创建Worker类处理时间检查和通知

这个类会在后台执行,负责对比当前时间和你的预设列表,匹配就发通知:

class TimeCheckWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
    override fun doWork(): Result {
        // 替换成你实际获取小时分钟列表的方法(比如从SharedPreferences/Room读取)
        val presetTimes = getPresetTimeList()
        val currentCalendar = Calendar.getInstance()
        val currentHour = currentCalendar.get(Calendar.HOUR_OF_DAY)
        val currentMinute = currentCalendar.get(Calendar.MINUTE)

        // 遍历列表检查时间匹配
        presetTimes.forEach { (hour, minute) ->
            if (hour == currentHour && minute == currentMinute) {
                sendMatchNotification(applicationContext)
            }
        }
        return Result.success()
    }

    private fun sendMatchNotification(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(
                "time_match_channel",
                "时间匹配提醒",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }
        val notification = NotificationCompat.Builder(context, "time_match_channel")
            .setContentTitle("时间匹配提醒")
            .setContentText("当前时间和你预设的时间一致啦!")
            .setSmallIcon(R.drawable.ic_notification) // 替换成你的通知图标
            .build()
        notificationManager.notify(System.currentTimeMillis().toInt(), notification)
    }

    private fun getPresetTimeList(): List<Pair<Int, Int>> {
        // 示例数据,实际替换成你的ArrayList读取逻辑
        return arrayListOf(Pair(9, 30), Pair(14, 0), Pair(18, 45))
    }
}

步骤2:调度Worker定期执行

在你的Application类或者启动页的onCreate()里,启动这个Worker,设置每分钟检查一次(因为要精确到分钟):

fun scheduleTimeCheckWorker(context: Context) {
    // 设置任务约束:不需要网络
    val constraints = Constraints.Builder()
        .setRequiredNetworkType(NetworkType.NOT_REQUIRED)
        .build()

    // 创建每分钟执行一次的重复任务
    val periodicRequest = PeriodicWorkRequestBuilder<TimeCheckWorker>(1, TimeUnit.MINUTES)
        .setConstraints(constraints)
        .build()

    // 唯一调度,避免重复创建任务
    WorkManager.getInstance(context).enqueueUniquePeriodicWork(
        "TimeCheckWorker",
        ExistingPeriodicWorkPolicy.REPLACE,
        periodicRequest
    )
}

方案二:用AlarmManager(适合精确定时)

如果你的时间列表是固定的、不需要频繁修改,AlarmManager会更高效——直接为每个预设时间点设置闹钟,到点就触发通知,不用定期检查。

步骤1:创建广播接收器接收闹钟触发

class TimeMatchAlarmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        context?.let { sendMatchNotification(it) }
    }

    private fun sendMatchNotification(context: Context) {
        // 和WorkManager里的通知代码一致,重复部分可以抽成工具类
        val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "time_match_channel",
                "时间匹配提醒",
                NotificationManager.IMPORTANCE_DEFAULT
            )
            notificationManager.createNotificationChannel(channel)
        }
        val notification = NotificationCompat.Builder(context, "time_match_channel")
            .setContentTitle("时间匹配提醒")
            .setContentText("当前时间和你预设的时间一致啦!")
            .setSmallIcon(R.drawable.ic_notification)
            .build()
        notificationManager.notify(System.currentTimeMillis().toInt(), notification)
    }
}

记得在AndroidManifest.xml里注册这个接收器:

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

步骤2:为每个预设时间设置闹钟

fun setupTimeMatchAlarms(context: Context, presetTimes: List<Pair<Int, Int>>) {
    val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
    presetTimes.forEachIndexed { index, (hour, minute) ->
        val intent = Intent(context, TimeMatchAlarmReceiver::class.java)
        // 每个闹钟用不同的requestCode,避免覆盖
        val pendingIntent = PendingIntent.getBroadcast(
            context,
            index,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )

        val alarmCalendar = Calendar.getInstance().apply {
            set(Calendar.HOUR_OF_DAY, hour)
            set(Calendar.MINUTE, minute)
            set(Calendar.SECOND, 0)
            // 如果当前时间已经过了预设点,设置到第二天
            if (timeInMillis < System.currentTimeMillis()) {
                add(Calendar.DAY_OF_YEAR, 1)
            }
        }

        // Android 12+需要精确闹钟权限,先检查再设置
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
            if (alarmManager.canScheduleExactAlarms()) {
                alarmManager.setExactAndAllowWhileIdle(
                    AlarmManager.RTC_WAKEUP,
                    alarmCalendar.timeInMillis,
                    pendingIntent
                )
            } else {
                // 引导用户开启精确闹钟权限
                val permissionIntent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM)
                permissionIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                context.startActivity(permissionIntent)
            }
        } else {
            alarmManager.setExactAndAllowWhileIdle(
                AlarmManager.RTC_WAKEUP,
                alarmCalendar.timeInMillis,
                pendingIntent
            )
        }
    }
}

还要在AndroidManifest.xml里添加权限:

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

最后补充

  • 如果你的时间列表会动态修改,WorkManager更灵活,每次执行时都会读取最新的列表;
  • 如果是固定时间点,AlarmManager更省电,不用频繁唤醒后台;
  • 测试的时候可以把预设时间改成当前时间的下一分钟,验证后台是否能触发通知。

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

火山引擎 最新活动