注:StackOverflowでここに記述されているさまざまなソリューションを試しました(ここの例)。あなたが見つけたものからのあなたの解決策が私が以下に書いたテストを使用して機能するかどうかをチェックせずにこれを閉じないでください。
バックグラウンド
アプリには、ユーザーがリマインダーを特定の時間にスケジュールするように設定するという要件があります。そのため、この時間にアプリがトリガーされると、バックグラウンドで小さな処理が行われ(DBクエリ操作のみ)、リマインダーについて伝えるための簡単な通知。
以前は、単純なコードを使用して、比較的特定の時間にスケジュールされるものを設定していました。
val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
val pendingIntent = PendingIntent.getBroadcast(context, requestId, Intent(context, AlarmReceiver::class.java), PendingIntent.FLAG_UPDATE_CURRENT)
when {
VERSION.SDK_INT >= VERSION_CODES.KITKAT -> alarmManager.setExact(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
else -> alarmManager.set(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
}
class AlarmReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
Log.d("AppLog", "AlarmReceiver onReceive")
//do something in the real app
}
}
使用法:
val timeToTrigger = System.currentTimeMillis() + java.util.concurrent.TimeUnit.MINUTES.toMillis(1)
setAlarm(this, timeToTrigger, 1)
問題
このコードを新しいAndroidバージョンのエミュレーターとAndroid 10を搭載したPixel 4でテストしましたが、トリガーされないようです。または、提供してから非常に長い時間後にトリガーされる可能性があります。私は、よく承知している恐ろしい行動することを、いくつかのOEMは、最近のタスクからアプリケーションを削除するに追加しましたが、この1はエミュレータとピクセル4デバイス(株)の両方です。
アラームの設定に関するドキュメントを読みましたが、アプリで制限されているため、あまり発生しませんが、これは特定の時間にアラームを設定する方法を説明しておらず、説明もしていませんどのように来るGoogleの時計アプリはそれをやって成功しました。
それだけでなく、私が理解しているところによると、制限は特にデバイスの低電力状態に適用する必要があると述べていますが、私の場合、デバイスとエミュレーターの両方でこの状態がありませんでした。約1分後にアラームがトリガーされるように設定しました。
多くの目覚まし時計アプリが以前のように機能しなくなったのを見て、ドキュメントに欠けているものがあると思います。このようなアプリの例としては、Googleが購入した人気のあるTimelyアプリがありますが、新しい制限を処理するための新しいアップデートを取得していません。。ただし、このアプリなど、一部の人気のあるアプリは正常に動作します。
私が試したこと
実際にアラームが機能することをテストするために、アプリを初めてインストールした後、デバイスがPCに接続されている間(ログを表示するため)に、数分後にアラームをトリガーしようとするときに、これらのテストを実行します。
- アプリがフォアグラウンドにあり、ユーザーに表示されるかどうかをテストします。-1〜2分かかりました。
- アプリがバックグラウンドに送信されたタイミングをテストします(たとえば、ホームボタンを使用)-約1分かかりました
- アプリのタスクが最近のタスクからいつ削除されたかをテストします。-20分以上待ちましたが、アラームがトリガーされてログに書き込まれていませんでした。
- #3と同じですが、画面もオフにします。それはおそらくもっと悪いでしょう...
私は次のものを使おうとしましたが、すべてうまくいきません:
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
上記のいずれかの組み合わせと:
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) alarmManager.setWindow(AlarmManager.RTC_WAKEUP, 0, 60 * 1000L, pendingIntent)
BroadcastReceiverの代わりにサービスを使用しようとしました。別のプロセスでも試してみました。
バッテリーの最適化からアプリを無視することを試みました(助けにはならなかった)が、他のアプリはそれを必要としないので、私もそれを使用すべきではない。
これを使ってみました:
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
- onTaskRemovedのトリガーを持つサービスを用意して、そこでアラームを再スケジュールしようとしましたが、これも役に立ちませんでした(サービスは正常に機能しました)。
Googleの時計アプリについては、トリガーされる前に通知が表示されることを除いて、特別なことは何もありませんでした。また、バッテリー最適化設定画面の「最適化されていません」セクションにも表示されません。
これはバグのように見えるので、サンプルプロジェクトと問題を示すビデオを含めて、ここで報告しました。
エミュレータの複数のバージョンを確認したところ、この動作はAPI 27(Android 8.1-Oreo)から始まったようです。docsを見ると、 AlarmManagerが言及されていないように見えますが、代わりに、さまざまなバックグラウンド作業について書かれています。
質問
現在、比較的正確な時間にトリガーされるように何かを設定するにはどうすればよいですか?
上記の解決策が機能しなくなったのはなぜですか?何か不足していますか?許可?代わりにワーカーを使用することになっているのでしょうか?しかし、それはそれが時間どおりにトリガーされない可能性があることを意味しませんか?
Googleの「時計」アプリは、これらすべてをどのように克服し、たとえちょうど1分前にトリガーされたとしても、常に正確な時間にトリガーしますか?それはシステムアプリだからというだけのことですか?それが組み込まれていないデバイスに、ユーザーアプリとしてインストールされた場合はどうなりますか?
システムアプリだからといって、ここで2分間に2回アラームをトリガーできるアプリをもう1つ見つけました。ただし、フォアグラウンドサービスを使用することもあると思います。
編集:ここで、アイデアを試すための小さなGithubリポジトリを作成しました。
編集:ようやくオープンソースであり、この問題のないサンプルが見つかりました。悲しいことに、それは非常に複雑であり、私はまだそれが何がそんなに違うのか(そして私が私のPOCに追加する必要がある最小限のコードは何ですか)を理解しようとします