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

如何实现应用在00:00或安装24小时后弹出Toast?

嘿,我来帮你搞定这个Toast触发的问题!你需要的两个场景(每日00:00弹出和安装后24小时弹出),靠轮询时间确实容易出问题,不如用Android官方推荐的定时任务组件来实现,稳定又省心,我给你一步步拆解:

一、先搞定「安装后24小时弹出Toast」

这个核心是先记录安装时间,再精准调度延迟任务:

  • 第一步:保存首次安装时间
    我们可以在App首次启动时,把安装时间存在SharedPreferences里,避免每次启动都重复记录:
    // 可以放在Application的onCreate或者第一个启动的Activity的onCreate里执行
    val sharedPref = getSharedPreferences("AppInstallRecord", Context.MODE_PRIVATE)
    if (!sharedPref.contains("first_install_time")) {
        // 获取应用首次安装的时间戳
        val installTime = packageManager.getPackageInfo(packageName, 0).firstInstallTime
        sharedPref.edit().putLong("first_install_time", installTime).apply()
    }
    
  • 第二步:用WorkManager调度延迟任务
    WorkManager是Google推荐的后台任务调度工具,能适配不同Android版本的后台限制,比自己轮询靠谱多了。计算好24小时后的触发时间,然后提交任务:
    val sharedPref = getSharedPreferences("AppInstallRecord", Context.MODE_PRIVATE)
    val installTime = sharedPref.getLong("first_install_time", 0)
    val targetTime = installTime + 24 * 60 * 60 * 1000L // 安装时间 + 24小时
    val delayMillis = targetTime - System.currentTimeMillis()
    
    if (delayMillis > 0) {
        // 创建单次执行的任务
        val showToastWork = OneTimeWorkRequestBuilder<InstallReminderWorker>()
            .setInitialDelay(delayMillis, TimeUnit.MILLISECONDS)
            .build()
        // 加入调度队列
        WorkManager.getInstance(this).enqueue(showToastWork)
    } else {
        // 如果已经超过24小时,直接弹出Toast
        Toast.makeText(this, "安装已超过24小时", Toast.LENGTH_SHORT).show()
    }
    
  • 第三步:实现Worker类弹出Toast
    注意Worker是在后台线程运行的,不能直接弹Toast,得切换到主线程:
    class InstallReminderWorker(context: Context, params: WorkerParameters) : Worker(context, params) {
        override fun doWork(): Result {
            // 切换到主线程显示Toast
            MainThreadExecutor().execute {
                Toast.makeText(applicationContext, "安装后24小时提醒", Toast.LENGTH_SHORT).show()
            }
            return Result.success()
        }
    }
    
二、再实现「每日00:00弹出Toast」

这里推荐用WorkManager的周期性任务,或者AlarmManager(适合需要更精准触发的场景):

方法1:用WorkManager实现每日定时触发

先计算距离下一个00:00的延迟时间,再设置周期性任务:

// 计算距离下一个00:00的毫秒数
fun calculateDelayToMidnight(): Long {
    val calendar = Calendar.getInstance()
    val now = calendar.timeInMillis
    // 把时间设置到明天00:00
    calendar.set(Calendar.HOUR_OF_DAY, 0)
    calendar.set(Calendar.MINUTE, 0)
    calendar.set(Calendar.SECOND, 0)
    calendar.set(Calendar.MILLISECOND, 0)
    calendar.add(Calendar.DAY_OF_MONTH, 1)
    return calendar.timeInMillis - now
}

// 调度每日任务
val delayToMidnight = calculateDelayToMidnight()
val dailyToastWork = PeriodicWorkRequestBuilder<MidnightToastWorker>(1, TimeUnit.DAYS)
    .setInitialDelay(delayToMidnight, TimeUnit.MILLISECONDS)
    .build()
// 用唯一名称避免重复调度
WorkManager.getInstance(this).enqueueUniquePeriodicWork(
    "DailyMidnightToast",
    ExistingPeriodicWorkPolicy.REPLACE,
    dailyToastWork
)

MidnightToastWorker的实现和上面的InstallReminderWorker几乎一样,只需要修改Toast的内容就行。

方法2:用AlarmManager实现精准触发(适合Android 12+以下)

如果需要更精准的触发,可以用AlarmManager,但要注意Android 12+的后台限制:

  • 注册BroadcastReceiver
    class MidnightAlarmReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            context?.let {
                Toast.makeText(it, "现在是00:00啦", Toast.LENGTH_SHORT).show()
                // 重新设置第二天的闹钟,避免系统重启后丢失
                setNextMidnightAlarm(it)
            }
        }
    }
    
  • 在Manifest里注册Receiver
    <receiver android:name=".MidnightAlarmReceiver" />
    
  • 实现设置闹钟的方法
    fun setNextMidnightAlarm(context: Context) {
        val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val intent = Intent(context, MidnightAlarmReceiver::class.java)
        val pendingIntent = PendingIntent.getBroadcast(
            context,
            0,
            intent,
            PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
        )
    
        val calendar = Calendar.getInstance()
        calendar.set(Calendar.HOUR_OF_DAY, 0)
        calendar.set(Calendar.MINUTE, 0)
        calendar.set(Calendar.SECOND, 0)
        calendar.set(Calendar.MILLISECOND, 0)
        // 如果当前时间已经过了00:00,就设置到第二天
        if (calendar.timeInMillis <= System.currentTimeMillis()) {
            calendar.add(Calendar.DAY_OF_MONTH, 1)
        }
    
        // 根据系统版本选择合适的闹钟类型
        if (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
            )
        }
    }
    
    最后在App启动时调用setNextMidnightAlarm(this)初始化闹钟即可。
三、几个关键注意事项
  • 后台线程不能直接弹Toast:不管是Worker还是BroadcastReceiver,都要切换到主线程再显示Toast,否则会报错。
  • 避免重复调度:比如安装后24小时的任务,最好用SharedPreferences记录是否已经调度过,避免每次启动App都重复添加任务。
  • 适配Android后台限制:Android 8+对后台任务有严格限制,WorkManager会自动适配,是更稳妥的选择;如果用AlarmManager,Android 12+需要申请POST_NOTIFICATIONS权限才能在后台触发。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:53:31