在 Android 中要建立精確時間的任務會使用 AlarmManager ,就算 App 沒有在啟動中也可以自動觸發,但是 AlarmManager 會比較耗電。
本文示範使用 AlarmManager 在指定的時間顯示 Toast 訊息。
要使用 AlarmManager 需要在 AndroidManifest.xml 中註冊權限:
建立一個 DTO 用來儲存通知資料
AlarmManager 任務依照時間觸發後會發送 Intent 廣播,這裡建立 MyAlarmBroadcastReceiver.kt,用來接收任務觸發後發送的 Intent 事件和訊息,並且將內容使用 Toast 顯示:
在 AndroidManifest.xml 中註冊 MyAlarmBroadcastReceiver.kt ,使其能夠接收廣播
建立 MyAlarmScheduler.kt ,方便使用 AlarmManager 建立和取消任務:
參考資料:
Android Developers - AlarmManager
本文示範使用 AlarmManager 在指定的時間顯示 Toast 訊息。
要使用 AlarmManager 需要在 AndroidManifest.xml 中註冊權限:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
</manifest>
建立一個 DTO 用來儲存通知資料
import java.time.LocalDateTime
data class MyAlarmDto(
val time: LocalDateTime, // 觸發時間
val message: String,
)
AlarmManager 任務依照時間觸發後會發送 Intent 廣播,這裡建立 MyAlarmBroadcastReceiver.kt,用來接收任務觸發後發送的 Intent 事件和訊息,並且將內容使用 Toast 顯示:
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.widget.Toast
class MyAlarmBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val data = intent.getStringExtra("data") ?: ""
Toast.makeText(context, "訊息: $data", Toast.LENGTH_SHORT).show()
}
}
在 AndroidManifest.xml 中註冊 MyAlarmBroadcastReceiver.kt ,使其能夠接收廣播
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM" />
<uses-permission android:name="android.permission.USE_EXACT_ALARM" />
<application>
<receiver android:name=".MyAlarmBroadcastReceiver"/>
</application>
</manifest>
建立 MyAlarmScheduler.kt ,方便使用 AlarmManager 建立和取消任務:
class MyAlarmScheduler(private val context: Context) {
private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
fun scheduleAlarm(item: MyAlarmDto) {
// 建立 Intent 並設定要傳遞的資料
val intent = Intent(context, MyAlarmBroadcastReceiver::class.java).apply {
putExtra("data", item.message)
}
// 建立 PendingIntent
val broadcast = PendingIntent.getBroadcast(
context, item.id, intent,
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
// 設定精確時間任務
alarmManager.setExactAndAllowWhileIdle(
AlarmManager.RTC_WAKEUP,
item.time.atZone(ZoneId.systemDefault()).toEpochSecond() * 1000, // 設定觸發時間
broadcast
)
}
fun cancelAlarm(item: MyAlarmDto) {
alarmManager.cancel(
PendingIntent.getBroadcast(
context,
item.id,
Intent(context, MyAlarmBroadcastReceiver::class.java),
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
)
}
}
建立和取消定時任務
這裡使用 Jetpack Compose 建立兩個最簡單的 Button 做示範,按下後就會建立 5 秒鍾執行的任務,也可以在觸發前取消
val content: Context = LocalContext.current
val myAlarmManager: MyAlarmScheduler = MyAlarmScheduler(content)
val myDto: MyAlarmDto = MyAlarmDto(
id = 1,
time = LocalDateTime.now().plusSeconds(5),
message = "測試訊息"
)
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.Center
) {
Button(onClick = {
myAlarmManager.scheduleAlarm(myDto)
}) {
Text("建立任務")
}
Button(onClick = {
myAlarmManager.cancelAlarm(myDto)
}) {
Text("取消任務")
}
}
參考資料:
Android Developers - AlarmManager
留言
張貼留言
如果有任何問題、建議、想說的話或文章題目推薦,都歡迎留言或來信: a@ruyut.com