ホーム
2022.7.20

kotlin アラーム(Alarm manager)を使って指定した時刻に通知する

ボタンを押したら2秒後に通知するサンプルアプリを作成しました。
通知の出し方についてはkotlin 通知するを参考にしてください。
Alarm managerに、日時と実行する内容をセットしています。
このプロジェクトではMyNotification.ktとMyReceiver.ktを追加で作成しています。

MyNotification.kt

package com.example.samplealarm

import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.Context
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat

class MyNotification {
fun sendNotification(context: Context) {
val channelId = "com.example.sample_notification"
val channelName = "my channel"
val channelDescription = "This is a sample notification."

//Android 8.0 以上ではアプリの通知チャンネルを登録することが必要。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //---*0
val importance = NotificationManager.IMPORTANCE_DEFAULT //---*1
val channel = NotificationChannel(channelId, channelName, importance).apply {
description = channelDescription
}
val manager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(channel)
}

//通知をシステムに登録しています。
val builder = NotificationCompat.Builder(context, channelId).apply {
setSmallIcon(R.drawable.ic_launcher_foreground) //---*2
setContentTitle("通知のタイトル")
setContentText("通知するメッセージ")
priority = NotificationCompat.PRIORITY_DEFAULT //---*3
}
val id = 0 //---*4
NotificationManagerCompat.from(context).notify(id, builder.build())

}
}

MyReceiver.kt

package com.example.samplealarm

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent

class MyReceiver : BroadcastReceiver() {
override fun onReceive(context: Context?, p1: Intent?) {
if(context != null) {
val myNotification = MyNotification()
myNotification.sendNotification(context)
}
}
}
ここでアラームが起動したときの処理を記述しています。 今回は通知を出しています。

MainActivity.kt

package com.example.samplealarm

import android.app.AlarmManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import com.example.samplealarm.databinding.ActivityMainBinding
import java.util.*

class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)

binding.btnTest.setOnClickListener {
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
val calendar = Calendar.getInstance()
val intent = Intent(this, MyReceiver::class.java)

val flag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
PendingIntent.FLAG_UPDATE_CURRENT + PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}

val pendingIntent = PendingIntent.getBroadcast(
this, 0, intent, flag
)

calendar.add(Calendar.SECOND, 2)
alarmManager.setExact(
AlarmManager.RTC,
calendar.timeInMillis,
pendingIntent
)
}
}
}
setExact()の引数ですが、
1つ目には4つの選択肢があります。
ELAPSED_REALTIME指定秒経過後に発生させる
ELAPSED_REALTIME_WAKEUP指定秒経過後にスリープ中でも解除して発生させる
RTC指定日時に発生させる
RTC_WAKEUP指定日時にスリープ中でも解除して発生させる
2つ目は指定秒、または指定日時です。
3つ目は実行したいintentが入ったpendingIntent。
(※Pending:保留中の、Intent:意図 という意味のようです)
1つ目の引数についてですが、ELAPSED~を選択すると2つ目の引数には今からのミリ秒を指定します。
一方RTC~を選択すると2つ目の引数には指定日時の値を指定(とても大きな値。10秒後だと今日の今の値に10秒を足す。)します。

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"
package="com.example.samplealarm">
<uses-permission android:name="android.permission.SCHEDULE_EXACT_ALARM"/><!--added-->

<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SampleAlarm"
tools:targetApi="31">
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".MyReceiver"
android:exported="false">
</receiver><!--added-->
</application>

</manifest>
<uses-permission>: アラームの発生はスマホに許可が必要なのでSCHEDULE_EXACT_ALARMのpermission設定を追記します。
<receiver>: アラームを受けて動作する機能を作ったためレシーバーを追記します。