Catatan: Saya mencoba berbagai solusi yang ditulis di sini di StackOverflow (contoh di sini ). Tolong jangan tutup ini tanpa memeriksa apakah solusi Anda dari apa yang Anda temukan bekerja menggunakan tes yang saya tulis di bawah ini.
Latar Belakang
Ada persyaratan pada aplikasi, bahwa pengguna menetapkan pengingat yang dijadwalkan pada waktu tertentu, jadi ketika aplikasi dipicu pada waktu ini, ia melakukan sesuatu yang kecil di latar belakang (hanya beberapa operasi permintaan DB), dan menunjukkan pemberitahuan sederhana, untuk memberi tahu tentang pengingat.
Di masa lalu, saya menggunakan kode sederhana untuk mengatur sesuatu agar dijadwalkan pada waktu yang relatif spesifik:
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
}
}
Pemakaian:
val timeToTrigger = System.currentTimeMillis() + java.util.concurrent.TimeUnit.MINUTES.toMillis(1)
setAlarm(this, timeToTrigger, 1)
Masalah
Saya sekarang telah menguji kode ini pada emulator pada versi Android baru dan pada Pixel 4 dengan Android 10, dan tampaknya tidak memicu, atau mungkin memicu setelah waktu yang sangat lama sejak apa yang saya berikan. Saya menyadari perilaku buruk yang ditambahkan beberapa OEM untuk menghapus aplikasi dari tugas-tugas terbaru, tetapi yang satu ini ada pada kedua emulator dan perangkat Pixel 4 (persediaan).
Saya sudah membaca dokumen tentang mengatur alarm, bahwa itu dibatasi untuk aplikasi sehingga tidak akan terlalu sering terjadi, tetapi ini tidak menjelaskan cara mengatur alarm pada waktu tertentu, dan itu tidak menjelaskan kenapa aplikasi Google Clock berhasil melakukannya.
Tidak hanya itu, tetapi menurut apa yang saya pahami, dikatakan bahwa pembatasan harus diterapkan terutama untuk kondisi daya perangkat yang rendah, tetapi dalam kasus saya, saya tidak memiliki status ini, baik pada perangkat maupun pada emulator. Saya sudah mengatur alarm untuk dipicu dalam sekitar satu menit dari sekarang.
Melihat bahwa banyak aplikasi jam alarm tidak berfungsi lagi seperti biasanya, saya pikir ada sesuatu yang hilang pada dokumen. Contoh aplikasi semacam itu adalah aplikasi Tepat Waktu yang populer yang dibeli oleh Google tetapi tidak pernah mendapat pembaruan baru untuk menangani pembatasan baru, dan sekarang pengguna menginginkannya kembali. . Namun, beberapa aplikasi populer berfungsi dengan baik, seperti yang ini .
Apa yang saya coba
Untuk menguji apakah memang alarmnya bekerja, saya melakukan tes-tes ini ketika mencoba memicu alarm dalam satu menit dari sekarang, setelah menginstal aplikasi untuk pertama kalinya, semuanya saat perangkat terhubung ke PC (untuk melihat log):
- Uji ketika aplikasi di latar depan, terlihat oleh pengguna. - butuh 1-2 menit.
- Tes ketika aplikasi dikirim ke latar belakang (menggunakan tombol home, misalnya) - membutuhkan waktu sekitar 1 menit
- Uji kapan tugas aplikasi dihapus dari tugas terbaru. - Saya menunggu lebih dari 20 menit dan tidak melihat alarm dipicu, menulis ke log.
- Seperti # 3, tetapi juga matikan layar. Mungkin akan lebih buruk ...
Saya mencoba menggunakan hal-hal selanjutnya, semua tidak berfungsi:
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
kombinasi salah satu di atas, dengan:
if (VERSION.SDK_INT >= VERSION_CODES.KITKAT) alarmManager.setWindow(AlarmManager.RTC_WAKEUP, 0, 60 * 1000L, pendingIntent)
Mencoba menggunakan layanan alih-alih BroadcastReceiver. Juga mencoba proses yang berbeda.
Mencoba membuat aplikasi diabaikan dari optimasi baterai (tidak membantu), tetapi karena aplikasi lain tidak membutuhkannya, saya juga tidak boleh menggunakannya.
Sudah mencoba menggunakan ini:
if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP)
alarmManager.setAlarmClock(AlarmManager.AlarmClockInfo(timeToTrigger, pendingIntent), pendingIntent)
AlarmManagerCompat.setExactAndAllowWhileIdle(alarmManager, AlarmManager.RTC_WAKEUP, timeToTrigger, pendingIntent)
- Sudah mencoba sebuah layanan yang akan memiliki pemicu onTaskRemoved , untuk menjadwalkan ulang alarm di sana, tetapi ini juga tidak membantu (layanannya bekerja dengan baik).
Adapun aplikasi Jam Google, saya tidak melihat sesuatu yang istimewa tentang hal itu kecuali bahwa itu menunjukkan pemberitahuan sebelum dipicu, dan saya juga tidak melihatnya di bagian "tidak dioptimalkan" pada layar pengaturan pengoptimalan baterai.
Melihat bahwa ini sepertinya bug, saya melaporkannya di sini , termasuk proyek sampel dan video untuk menunjukkan masalah tersebut.
Saya telah memeriksa beberapa versi emulator, dan tampaknya perilaku ini dimulai dari API 27 (Android 8.1 - Oreo). Melihat dokumen , saya tidak melihat AlarmManager disebutkan, tetapi sebaliknya, itu ditulis tentang berbagai latar belakang pekerjaan.
Pertanyaan-pertanyaan
Bagaimana kita mengatur sesuatu untuk dipicu pada waktu yang relatif tepat saat ini?
Kenapa solusi di atas tidak berfungsi lagi? Apakah saya kehilangan sesuatu? Izin? Mungkin saya seharusnya menggunakan Pekerja sebagai gantinya? Tapi bukankah itu berarti itu mungkin tidak memicu waktu sama sekali?
Bagaimana aplikasi "Jam" Google mengatasi semua ini, dan tetap memicu pada waktu yang tepat, selalu, bahkan jika dipicu hanya beberapa menit yang lalu? Apakah hanya karena itu aplikasi sistem? Bagaimana jika itu diinstal sebagai aplikasi pengguna, pada perangkat yang tidak memilikinya built-in?
Jika Anda mengatakan itu karena itu adalah aplikasi sistem, saya telah menemukan aplikasi lain yang dapat memicu alarm dua kali dalam 2 menit, di sini , meskipun saya pikir itu kadang-kadang menggunakan layanan latar depan.
EDIT: membuat repositori Github kecil untuk mencoba ide, di sini .
EDIT: akhirnya menemukan sampel yang bersumber terbuka dan tidak memiliki masalah ini. Sayangnya itu sangat kompleks dan saya masih mencoba mencari tahu apa yang membuatnya sangat berbeda (dan apa kode minimal yang harus saya tambahkan ke POC saya) yang memungkinkan alarmnya tetap dijadwalkan setelah menghapus aplikasi dari tugas-tugas terbaru