LoginSignup
23
23

More than 5 years have passed since last update.

複数の不要なAlarmをまとめてCancelする方法を考える(Android)

Last updated at Posted at 2016-07-02

目覚まし時計アプリだったり、定期的なプッシュ通知を出すなどに便利なAlarm。
しかし、複数のアラームをセットした時がなかなか曲者です。
不要なアラームはまとめて削除したい。その方法を考えます。

結論としては、requestCodeを変えて登録しておくと良い、と言った感じです(詳しくは後半)。

前提

複数登録するアラームは、同じBroadcastReceiverを呼びます。

Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);

// AlarmReceiver: アラーム起動で呼ばれるクラス、BroadcastReceiverをextendsしてある

基本的な登録と削除の方法 (1つの場合)

基本的には、登録したIntentと同じIntentを使用してキャンセルします。
コードを見るのが早いと思うので、実装を以下に。

登録
// アラームの登録
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);

alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent);

// calendar: Calendarのインスタンス、アラームが起動する時刻を設定してある
// AlarmReceiver: アラーム起動で呼ばれるクラス、BroadcastReceiverをextendsしてある
削除
// アラームの削除
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);

pendingIntent.cancel();
alarmManager.cancel(pendingIntent);

見ての通り、登録・削除で違いがあるのは、AlarmManagerにsetしているかcancelしているか程度です。
alarmManagerだけキャンセルしてもできるようですが、pendingIntentもcancelしておくほうが良さそうです。。。

複数のAlarmを登録・削除する場合

今回の場合は、特に「Receiverが同じ」場合です。ここでは、複数のパターンを考えます

Intent.setTypeを使うパターン

intent.setType()を使用して、別のintentであることを明確にするパターンです。
まずは、実装例を見てみます。

登録処理

登録
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

Intent intent1 = new Intent(getApplicationContext(), AlarmReceiver.class);
intent1.setType("first alarm");    // このsetTypeが重要
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(getApplicationContext(), 0, intent1, 0);
alarmManager.setRepeating(AlarmManager.RTC, calendar1.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent1);

Intent intent2 = new Intent(getApplicationContext(), AlarmReceiver.class);
intent2.setType("second alarm");    // このsetTypeが重要
PendingIntent pendingIntent2 = PendingIntent.getBroadcast(getApplicationContext(), 0, intent2, 0);
alarmManager.setRepeating(AlarmManager.RTC, calendar2.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent2);

上のコードではsetTypeでintentを区別するようにしました。
実際に、以下のコードでintentが区別されていることを確認することができます。

intent1.filterEquals(intent2);    // returns false.

setTypeしなかった場合

intent1.filterEquals(intent2);     // returns true.

intent1.putExtra(..., ...);
intent1.filterEquals(intent2);     // returns true.

intent.putExtraとかしても、trueになる = 同じintentとして扱われるのでご注意。setTypeが重要です。

削除処理

例によって、同じインテントを作って、削除するので、ここでもsetTypeが重要です。
先にセットした2つのアラームのうち、2つめを削除する例を挙げてみます。

削除処理
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
intent.setType("second alarm");    // このsetTypeが重要

PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, intent, 0);

pendingIntent.cancel();
alarmManager.cancel(pendingIntent);

これで2つめのアラームだけをキャンセルすることができました!

setTypeの問題点

setTypeで、intentを区別することができる事がわかりました。しかし、問題点もあります。

すべてキャンセルしたい時の処理が地味に面倒

仮に、アプリのアップデート時に過去のアラームをすべて削除する場合、過去に使用したアラームのタイプをすべてチェックして、削除する必要があります。
すべてのユーザが、直前のバージョンからアップデートするわけではありませんので、過去のタイプを、持ち続けなければならないんですね。。。

(むしろアプリを再インストールしてもらいたい)

requestCodeを分けるパターン

上では、setTypeでintentを区別する方法を上げましたが、キャンセル処理が面倒だということがわかりました。もっとすっきり考えられる方法はないのか。
ここではrequestCodeを使った方法を考えます。

登録と削除を一気に処理

基本的には、requestCodeをincrementしていく運用を考えます。
そうすれば、必要なrequestCodeより小さいものは全てキャンセルする処理が可能になります。

登録
int ACTIVE_REQUEST_CODE = 12;    // たとえば、requestCodeが12以上のアラームを有効にしておくとして

AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

// 不要になった過去のアラームをまとめて削除する
// requestCodeを0から登録していたとする
for (int requestCode = 0; requestCode < ACTIVE_REQUEST_CODE; requestCode++) {
    Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), requestCode, intent, 0);

    pendingIntent.cancel();
    alarmManager.cancel(pendingIntent);
}

// 新しいアラームの登録、必要なアラームの再登録
Intent intent = new Intent(getApplicationContext(), AlarmReceiver.class);
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), ACTIVE_REQUEST_CODE, intent, 0);
alarmManager.setRepeating(AlarmManager.RTC, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY * 7, pendingIntent);

この実装にしておけば、アップデートで一気にアラーム周りを刷新する場合においても、簡潔なコードで書けるのではないかなと予想しております。

結論

以上のような検討から、やはり、
アラームを複数登録する場合は、その後の運用も考えて、requestCodeをincrementして登録していくのが良さそう!!

23
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
23