如何在Android Studio中创建定时器并在计时结束时发送通知
嘿,这个需求我之前做过好几次,其实拆成两部分就搞定:实现可靠的定时器 + 到点触发系统通知。下面一步步给你讲清楚,不同场景下的实现方式都有:
Android里定时器的选择得看你的需求是短期前台使用还是长期后台可靠触发,两种场景推荐不同的方案:
场景1:短期定时器(比如几分钟内,应用保持前台)
这种情况用Handler.postDelayed最方便,代码简单,适合快速实现:
import android.os.Handler import android.os.Looper import androidx.appcompat.app.AppCompatActivity class TimerActivity : AppCompatActivity() { private val handler = Handler(Looper.getMainLooper()) private lateinit var timerRunnable: Runnable // 启动定时器,delayMillis是延迟的毫秒数 fun startShortTimer(delayMillis: Long) { timerRunnable = Runnable { // 时间到!触发通知 sendNotification() } handler.postDelayed(timerRunnable, delayMillis) } // 一定要在页面销毁时移除回调,避免内存泄漏 override fun onDestroy() { super.onDestroy() handler.removeCallbacks(timerRunnable) } }
⚠️ 注意:如果应用退到后台,系统可能会回收进程,导致定时器失效,所以这个方案只适合应用在前台的场景。
场景2:长期/后台可靠定时器
如果需要定时器在后台甚至应用重启后还能触发,推荐用Jetpack的WorkManager,它是Google官方推荐的后台任务调度组件,能适配Android的后台限制:
第一步:添加依赖
在你的app/build.gradle(Module级别)里添加WorkManager依赖:
dependencies { implementation "androidx.work:work-runtime-ktx:2.8.1" }
第二步:创建Worker类
Worker是WorkManager执行任务的载体,我们在这里写触发通知的逻辑:
import android.content.Context import androidx.work.Worker import androidx.work.WorkerParameters class TimerWorker(context: Context, params: WorkerParameters) : Worker(context, params) { override fun doWork(): Result { // 时间到,发送通知 sendNotification(applicationContext) return Result.success() // 任务执行成功 } }
第三步:调度Worker
在你的Activity/ViewModel里调用这段代码,设置延迟时间:
import androidx.work.OneTimeWorkRequestBuilder import androidx.work.WorkManager import java.util.concurrent.TimeUnit fun scheduleLongTimer(delayMillis: Long) { val timerWorkRequest = OneTimeWorkRequestBuilder<TimerWorker>() .setInitialDelay(delayMillis, TimeUnit.MILLISECONDS) .build() WorkManager.getInstance(applicationContext).enqueue(timerWorkRequest) }
这个方案即使应用被杀死,只要设备开机,时间到了就会触发任务。
不管用哪种定时器,到点后都要发送通知,这里要注意Android的权限和版本适配:
1. 配置权限和通知渠道
首先在AndroidManifest.xml里添加通知权限(Android 13+必须):
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
Android 8.0(API 26)及以上必须创建通知渠道,不然通知不会显示。
2. 编写发送通知的函数
把这个函数放到你的Activity或者Worker里(注意Worker用ApplicationContext):
import android.app.NotificationChannel import android.app.NotificationManager import android.app.PendingIntent import android.content.Context import android.content.Intent import android.os.Build import androidx.core.app.NotificationCompat import androidx.core.app.NotificationManagerCompat fun sendNotification(context: Context) { val channelId = "timer_notification_channel" val channelName = "定时器提醒" // 创建通知渠道(Android 8.0+) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val channel = NotificationChannel( channelId, channelName, NotificationManager.IMPORTANCE_DEFAULT ).apply { description = "定时器到达指定时间时的提醒通知" } val notificationManager = context.getSystemService(NotificationManager::class.java) notificationManager.createNotificationChannel(channel) } // 点击通知后打开应用主页 val launchIntent = context.packageManager.getLaunchIntentForPackage(context.packageName)?.apply { flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK } val pendingIntent = PendingIntent.getActivity( context, 0, launchIntent, PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE ) // 构建通知 val notification = NotificationCompat.Builder(context, channelId) .setSmallIcon(R.drawable.ic_notification) // 替换成你的通知图标(必须设置) .setContentTitle("定时器提醒") .setContentText("时间到啦!") .setPriority(NotificationCompat.PRIORITY_DEFAULT) .setContentIntent(pendingIntent) .setAutoCancel(true) // 点击通知后自动消失 .build() // 发送通知 with(NotificationManagerCompat.from(context)) { notify(1001, notification) // 1001是通知ID,可自定义 } }
3. 动态申请通知权限(Android 13+)
如果你的应用目标是Android 13(API 33)及以上,需要动态申请通知权限:
import android.Manifest import android.content.pm.PackageManager import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AppCompatActivity import androidx.core.content.ContextCompat class TimerActivity : AppCompatActivity() { private lateinit var requestNotificationPermission: ActivityResultLauncher<String> override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 初始化权限请求Launcher requestNotificationPermission = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted -> if (isGranted) { // 权限已授予,可以正常发送通知 } else { // 权限被拒绝,提示用户去设置里开启 } } // 检查权限 checkNotificationPermission() } private fun checkNotificationPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) { requestNotificationPermission.launch(Manifest.permission.POST_NOTIFICATIONS) } } } }
- 通知图标一定要用纯色的矢量图,不然在某些设备上会显示成白色方块。
- 如果用WorkManager,Worker里不能直接更新UI,所有和UI相关的操作要通过通知或者广播实现。
- 测试后台定时器的时候,不要用模拟器的“强制停止”,因为强制停止后WorkManager也不会触发,要模拟正常的应用退后台场景。
内容的提问来源于stack exchange,提问作者aaniish

