[Kotlin] AlarmManagerとPendingIntentで数秒後に遅延実行

2018年4月26日(更新: 2018年4月26日)

Androidアプリで、未来の指定した時間に処理を行うには AlarmManagerPendingIntent を組み合わせて使用する方法があります。

今回は Kotlin で、5秒後に処理を行う簡単な遅延実行プログラムの書き方を紹介します。

遅延実行するサンプルアプリ

サンプルアプリの全プログラムです。

アプリの見た目はボタンがひとつ表示されているだけの簡単なものです。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val layout = LinearLayout(this)
        setContentView(layout)

        // ボタンを作成
        val button = Button(this)
        button.setText("実行")
        layout.addView(button)

        // ボタンをタップした時の処理
        button.setOnClickListener {

            // 実行する時間(ミリ秒)
            val alarmTime = System.currentTimeMillis() + 5000

            // 実行したいクラスから Intent を作成
            val alarmIntent = Intent(this, AlarmReceiver::class.java)
            val pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_UPDATE_CURRENT)
            
            // AlarmManager で pendingIntent を指定時間後に実行するように設定
            val manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
            manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);
        }
    }
}

// 指定時間に呼び出されるクラス
// マニフェストにタグを追記するのを忘れずに
class AlarmReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        Toast.makeText(context, "処理が遅延実行された!", Toast.LENGTH_LONG).show()
    }
}

ボタンを押すと、5秒後に以下のメッセージ(Toast)が表示されます。

BroadcastReceiverで遅延表示したToastのメッセージ

アプリがバックグラウンドになってもメッセージが表示されます。

アプリがバックグラウンドでも表示されるBroadcastReceiver

プログラムの詳細

ボタンをタップした時に、以下の処理を順番に行っています。

実行する時間の設定

一般的に AlarmManager で処理を実行させる時間の指定は「今から何ミリ秒後」ではなく「基準となる時間から何ミリ秒後」となります。通常は協定世界時(UTC 1970年1月1日0時)が基準となります。

したがって、現在の時間のミリ秒を System.currentTimeMillis で取得して、それに5000ミリ秒を足すことで5秒後を表現しています。

System.currentTimeMillis() + 5000

PendingIntentの設定

実行したいクラス(今回はプログラム下部のAlarmReceiver)から Intent を作成し、それを PendingIntent のクラスメソッド getBroadcast の中身とします。

val alarmIntent = Intent(this, AlarmReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, alarmIntent, PendingIntent.FLAG_CANCEL_CURRENT)

(getBroadcast の各引数については詳解しませんので下記参考ドキュメントをご覧ください)

AlarmManager で遅延実行したいクラスは BroadcastReceiver を継承します。

これを継承したクラスを実行できるようにするには、マニフェスト(AndroidManifest.xml)に以下のように追記します。追記を忘れてもエラーにはなりませんが、クラスの呼び出しも行われないため注意して下さい。

<application

    ...
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <receiver android:name=".AlarmReceiver"></receiver>
</application>

AlarmManagerで遅延実行を設定

上記のように設定した実行時間(alarmTime)と処理を行うクラスの情報(pendingIntent)を元に遅延実行(アラーム)を設定します。

val manager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);

AlarmManager を getSystemService で取得し、メソッド setExact で実行タイミングと実行する PendingIntent を指定します。

setExact の第1引数はフラグであり AlarmManager.RTC_WAKEUP を設定すると、デバイスがスリープ状態でアラームを受け取った場合にスリープを解除するそうです。詳しくは下記参考の AlarmManager のドキュメントをご覧ください。

以上が AlarmManager と PendingIntent で遅延実行処理を行う基本となります。

カレンダーで実行時間を設定

先程はプログラムを実行してからの秒数で処理実行時間を設定していましたが、現実的には日時を指定すると思います。

これは、カレンダークラス(Calendar)を使用することで設定できます。

// カレンダーで日時を設定(2018/4/27 7:30:00)
var calendar = Calendar.getInstance()
calendar.set(2018, 3, 27, 7, 30, 0)

// 設定した日時のミリ秒を取得
val alarmTime = calendar.timeInMillis

...

manager.setExact(AlarmManager.RTC_WAKEUP, alarmTime, pendingIntent);

月(month)は 0 が 1月 なので注意して下さい。

参考

PendingIntent  |  Android Developers

AlarmManager  |  Android Developers

System (Java Platform SE 7 ) currentTimeMillis

コメントを残す

メールアドレスが公開されることはありません。