アラームマネージャーを使用してアラームをスケジュールするときにこのエラーが発生します
am.setExact(AlarmManager.RTC_WAKEUP, timeMillis, pendingIntent);
エラーは次のとおりです
Java.lang.SecurityException: !@Too many alarms (500) registered from pid 10790 uid 10206
at Android.os.Parcel.readException(Parcel.Java:1540)
at Android.os.Parcel.readException(Parcel.Java:1493)
at Android.app.IAlarmManager$Stub$Proxy.set(IAlarmManager.Java:206)
at Android.app.AlarmManager.setImpl(AlarmManager.Java:428)
at Android.app.AlarmManager.setExact(AlarmManager.Java:376)
このエラーが発生する理由と修正方法。
コメントが示唆するものとは異なり、これはあなたのせいではないかもしれません。これは3月中旬にプロダクションコードで発生し始めました。これは、最近リリースされ始めたLollipopを搭載したSamsungでのみ発生します。
更新:この問題は、利用可能な電話の1つで最終的に発生しました。
@goncalossilvaが言ったように、問題はFLAG_CANCEL_CURRENT
の使用によるものだと言っていますが、サムスンはアラームの量に500の上限を設けているようで、他のベンダーにはこの制限はありません。
FLAG_CANCEL_CURRENT
でPendingIntent
を作成すると、保留中の意図をキャンセルします(明らかに)アラームをキャンセルしません(明らかに)、後で新しい保留中のインテントを使用してアラームをキャンセルした場合アラームをキャンセルします(Intent.filterEquals
はtrue
である必要があるため、それほど明確ではありません)。そうは言っても、保留中のインテントがキャンセルされたため、古いアラームは実際には発動しないので、FLAG_UPDATE_CURRENT
を切り替えてバグを導入する心配はありません。
FLAG_UPDATE_CURRENT
に変更した後にデバイスを再起動する必要性に関しては、再起動する必要はありません。新しいアラーム用の新しいスロットがあるように、アラームの1つが発動するのを待つだけです。
このコードを試して問題を再現し、FLAG_UPDATE_CURRENT
に変更して何が起こるかを確認できます。また、"adb Shell dumpsys alarm"
を実行して、生成されたすべてのアラームを表示する必要があります
AlarmManager alarmManager = (AlarmManager) this.getSystemService(Context.ALARM_SERVICE);
for (int i = 0; i<1000; i++)
{
Intent intent = new Intent("FOOFOOFOO");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
alarmManager.cancel(pendingIntent);
long firstTime = SystemClock.elapsedRealtime() + 1000;
alarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, firstTime, pendingIntent);
}
Lollipopを実行しているSamsungデバイスでのみこの問題が発生する場合は、おそらくPendingIntent
sでFLAG_CANCEL_CURRENT
を使用しています。 FLAG_UPDATE_CURRENT
(必要に応じて他の調整を行う)に切り替えると、問題は解決します。
私の完全に根拠のない推測は、サムスンがキャンセルされたPendingIntent
をすぐには削除せずに削除のためにマークし、それをあまり頻繁に行わないFLAG_CANCEL_CURRENT
でいくつかの「最適化」を行っていることですまったく?)。
編集
この問題が発生したデバイスは、再起動されるかアプリが再インストールされるまで壊れた状態(PendingIntent
s?で埋められます)になることがわかりました。
Neverアラームの設定時に使用するPendingIntentsでFLAG_CANCEL_CURRENTを使用します。アラームを別の時間に再スケジュールする場合は、フラグはまったく必要ありません。フラグがゼロの複製PendingIntentを作成し、それを使用してアラームをset()します。これにより、既存のアラームが暗黙的にキャンセルされ、新しく指定された時間に設定されます。ただし、新しいPendingIntentを作成したときにFLAG_CANCEL_CURRENTを使用した場合は、現在キャンセルされたPendingIntentと「同じ」ことを認識するアラームマネージャーの機能が失われ、古いものがぶら下がり、配信不能になり、メモリを占有しますおよびCPU。このバグのあるアプリがシステム内に文字通り何百もの古いアラームを蓄積しているのを見たことがあります。これは顕著なパフォーマンスとメモリ使用量のヒットに十分なものです。
実際に既存のアラームのスケジュールを変更せずにエクストラを変更したいだけなら、それがFLAG_UPDATE_CURRENTの目的です。アラームを再スケジュールまたはキャンセルする場合は、フラグに0を使用します。
Samsungデバイス上の最新のLollipopビルドでは、登録できるアラームの数が制限されているようです。常に最大でX個のアラームを登録するだけで、アプリの問題を一時的に修正しました(X = 50を任意に選択しましたが、エラーメッセージで判断すると、最大499まで行くことができます。これはテストしていません。しかしながら)。
私は1週間前にこの一時的な修正を含むバージョンをリリースしましたが、それ以来このクラッシュは報告されていません。
私にとって_FLAG_UPDATE_CURRENT
_だけに変更しても、pendingIntents(_adb Shell dumpsys alarm > dump.txt
_で見られる)の複数のエントリを取り除くのに役立ちませんでした。
保留中のインテントをキャンセルする方法を変更することで修正しました
_PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT).cancel();
_
に
_PendingIntent pi = PendingIntent.getBroadcast(context, requestCode, intent, PendingIntent.FLAG_UPDATE_CURRENT).cancel();
alarmManager.cancel(pi);
_
これは、.getBroadcast()
および.getService()
に必要でした。興味深いことに、.getActivity()
ではそうではありませんでした。悲しいことに、なぜそうなのか、私には見当もつかない。
Android 5.0.1。を使用したSamsung Galaxy S4のすべて。