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

Android后台服务实现日历APP后台每日事件推送提醒方案咨询

实现Android日历APP后台每日事件提醒方案

嘿,这个需求其实可以通过WorkManager + 通知组件配合你现有的SharedPreferences存储来实现——毕竟普通后台Service在Android的各种省电策略下很容易被干掉,WorkManager是Google官方推荐的可靠后台任务调度方案,能适配从API 14到最新版本的系统。我给你一步步拆解实现步骤:

一、先优化SharedPreferences的存储结构

既然要按日期查询事件,建议用**标准日期格式(比如yyyy-MM-dd)**作为SharedPreferences的key,把对应日期的事件列表序列化成JSON字符串作为value存储。这样后续查询当天事件时,直接生成当天的标准日期key就能快速取出数据。

示例代码(保存事件):

// 假设你有一个Event数据类
data class Event(val id: String, val title: String, val desc: String)

// 保存事件到指定日期
fun saveEventToDate(context: Context, date: String, event: Event) {
    val sharedPref = context.getSharedPreferences("CalendarEvents", Context.MODE_PRIVATE)
    val editor = sharedPref.edit()
    
    // 先取出该日期已有的事件列表
    val existingEventsJson = sharedPref.getString(date, "[]")
    val existingEvents = Gson().fromJson(existingEventsJson, Array<Event>::class.java).toMutableList()
    existingEvents.add(event)
    
    // 重新存回SharedPreferences
    val updatedEventsJson = Gson().toJson(existingEvents)
    editor.putString(date, updatedEventsJson)
    editor.apply()
}

二、用WorkManager实现每日定时检查任务

1. 创建自定义Worker类

这个Worker就是执行每日检查逻辑的核心,在doWork()方法里完成「获取当前日期→查询SharedPreferences→有事件就发通知」的流程:

class DailyEventCheckWorker(context: Context, params: WorkerParameters) : CoroutineWorker(context, params) {
    override suspend fun doWork(): Result {
        // 1. 获取当前日期(格式和存储的key一致)
        val currentDate = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date())
        
        // 2. 从SharedPreferences查询当天事件
        val sharedPref = applicationContext.getSharedPreferences("CalendarEvents", Context.MODE_PRIVATE)
        val eventsJson = sharedPref.getString(currentDate, "[]")
        val events = Gson().fromJson(eventsJson, Array<Event>::class.java).toList()
        
        // 3. 如果有事件,发送通知
        if (events.isNotEmpty()) {
            sendEventNotification(events)
        }
        
        return Result.success()
    }
    
    private fun sendEventNotification(events: List<Event>) {
        val notificationManager = applicationContext.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        
        // Android 8.0+ 需要创建通知渠道
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                "calendar_event_channel",
                "日历事件提醒",
                NotificationManager.IMPORTANCE_DEFAULT
            ).apply {
                description = "每日日历事件通知"
            }
            notificationManager.createNotificationChannel(channel)
        }
        
        // 构建通知内容
        val eventTitles = events.joinToString("\n") { it.title }
        val notification = NotificationCompat.Builder(applicationContext, "calendar_event_channel")
            .setSmallIcon(R.drawable.ic_calendar_notification)
            .setContentTitle("今日有${events.size}个事件")
            .setContentText(eventTitles)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .build()
        
        // 发送通知(用时间戳作为id,避免覆盖)
        notificationManager.notify(System.currentTimeMillis().toInt(), notification)
    }
}

2. 调度周期性任务

在APP启动时(比如Application的onCreate()方法,或者MainActivity的onCreate()),提交这个每日执行的任务:

// 调度每日检查任务
fun scheduleDailyEventCheck(context: Context) {
    val dailyWorkRequest = PeriodicWorkRequestBuilder<DailyEventCheckWorker>(1, TimeUnit.DAYS)
        // 可选:设置任务首次执行的延迟,比如开机后10分钟
        .setInitialDelay(10, TimeUnit.MINUTES)
        .build()
    
    // 用UniqueWork确保同一任务只存在一个实例,避免重复调度
    WorkManager.getInstance(context).enqueueUniquePeriodicWork(
        "DailyEventCheck",
        ExistingPeriodicWorkPolicy.KEEP,
        dailyWorkRequest
    )
}

三、必要的权限配置

  • AndroidManifest.xml里声明通知权限:
<!-- Android 13+ 需要的通知权限 -->
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
  • 如果你的APP是Android 13及以上版本,记得在代码里动态申请POST_NOTIFICATIONS权限,否则通知发不出来。

四、关键注意事项

  • 日期格式一致性:一定要确保生成当前日期的格式和存储时用的key完全一致,否则会查不到数据(比如别一会用yyyy/MM/dd一会用yyyy-MM-dd)。
  • WorkManager的周期性限制:Android系统规定PeriodicWorkRequest的最小重复间隔是15分钟,我们设置1天是符合要求的,系统会尽量在每天的同一时间执行任务,但如果设备处于深度休眠状态,可能会延迟到设备唤醒后执行。
  • 避免任务重复:用enqueueUniquePeriodicWork而不是普通的enqueue,这样就算APP多次启动,也不会重复创建任务。

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

火山引擎 最新活动