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
sumber
Jawaban:
Kami tidak punya apa-apa untuk dilakukan.
Setelah aplikasi Anda tidak masuk daftar putih itu akan selalu terbunuh begitu dihapus dari aplikasi terbaru.
Karena Original Equipment Manufacturer (OMEs) terus-menerus melanggar kepatuhan Android .
Jadi, Jika aplikasi Anda tidak masuk daftar putih dari perangkat Memproduksi, aplikasi itu tidak akan memadamkan alarm latar belakang apa pun - jika aplikasi Anda dihapus dari aplikasi terbaru.
Anda dapat menemukan daftar perangkat dengan perilaku itu di sini JUGA Anda mungkin menemukan solusi samping, Namun, itu tidak akan berfungsi dengan baik.
sumber
Menemukan solusi aneh (contoh di sini ) yang tampaknya berfungsi untuk semua versi, termasuk bahkan Android R:
Di Android R Anda juga harus memberikannya. Sebelumnya, sepertinya tidak perlu dikabulkan, hanya dideklarasikan. Tidak yakin mengapa ini berubah pada R, tetapi saya dapat mengatakan bahwa SAW dapat diminta sebagai solusi yang memungkinkan untuk memulai sesuatu di latar belakang, seperti yang ditulis di sini untuk Android 10.
FakeActivity.kt
Anda juga dapat membuat Kegiatan ini hampir tidak terlihat oleh pengguna menggunakan tema ini:
Sayangnya, ini adalah solusi yang aneh. Saya berharap dapat menemukan solusi yang lebih baik untuk ini.
Pembatasan ini berbicara tentang memulai Activity, jadi ide saya saat ini adalah bahwa mungkin jika saya memulai layanan foreground untuk sepersekian detik, itu juga akan membantu, dan untuk ini saya bahkan tidak memerlukan izin SAW.
EDIT: OK saya mencoba dengan layanan latar depan (contoh di sini ), dan tidak berhasil. Tidak tahu mengapa suatu Kegiatan berfungsi tetapi bukan layanan. Saya bahkan mencoba untuk menjadwalkan ulang alarm di sana dan mencoba untuk membiarkan layanan tetap sebentar, bahkan setelah menjadwalkan ulang. Juga mencoba layanan normal tetapi tentu saja menutup segera, karena tugas itu dihapus, dan itu tidak berfungsi sama sekali (bahkan jika saya membuat utas untuk berjalan di latar belakang).
Solusi lain yang mungkin saya tidak coba adalah memiliki layanan latar depan selamanya, atau setidaknya sampai tugas dihapus, tapi ini agak aneh dan saya tidak melihat aplikasi yang saya sebutkan menggunakannya.
EDIT: mencoba menjalankan layanan latar depan sebelum menghapus tugas aplikasi, dan untuk beberapa saat setelahnya, dan alarm tetap bekerja. Juga mencoba agar layanan ini menjadi orang yang bertanggung jawab atas acara yang dihapus tugas, dan segera menutup sendiri ketika terjadi, dan masih berfungsi (contoh di sini ). Keuntungan dari solusi ini adalah bahwa Anda tidak harus memiliki izin SAW sama sekali. Kerugiannya adalah Anda memiliki layanan dengan notifikasi sementara aplikasi sudah terlihat oleh pengguna. Saya ingin tahu apakah mungkin untuk menyembunyikan pemberitahuan saat aplikasi sudah berada di latar depan melalui Aktivitas.
EDIT: Sepertinya ini bug di Android Studio (dilaporkan di sini , termasuk video yang membandingkan versi). Saat Anda meluncurkan aplikasi dari versi bermasalah yang saya coba, ini dapat menyebabkan alarm dihapus.
Jika Anda meluncurkan aplikasi dari peluncur, itu berfungsi dengan baik.
Ini adalah kode saat ini untuk mengatur alarm:
Saya bahkan tidak harus menggunakan "pendingShowList". Menggunakan null juga ok.
sumber
SYSTEM_ALERT_WINDOW
izin?Intent.FLAG_RECEIVER_FOREGROUND
bendera.https://developer.android.com/about/versions/oreo/background#broadcasts
setExactAndAllowWhileIdle()
saat menargetkan API 23+.https://developer.android.com/about/versions/oreo/background#migration
sumber
Saya tahu ini tidak efisien tetapi mungkin lebih konsisten dengan akurasi 60 detik.
https://developer.android.com/reference/android/content/Intent#ACTION_TIME_TICK
jika penerima siaran ini digunakan di dalam layanan latar depan, Anda dapat memeriksa waktu setiap menit dan membuat keputusan untuk mengambil tindakan.
sumber
Saya pikir Anda dapat meminta pengguna untuk mengatur izin sehingga menonaktifkan mode hemat energi, dan memperingatkan pengguna bahwa jika dia tidak menggunakannya, waktu yang tepat tidak akan tercapai.
Berikut kode untuk memintanya:
sumber
Saya adalah penulis proyek open source yang telah Anda sebutkan dalam pertanyaan Anda ( jam alarm sederhana) .
Saya terkejut bahwa menggunakan AlarmManager.setAlarmClock tidak berfungsi untuk Anda, karena aplikasi saya melakukan hal itu. Kode tersebut ada dalam file AlarmSetter.kt. Berikut ini cuplikannya:
Pada dasarnya itu tidak ada yang istimewa, hanya memastikan bahwa niat memiliki aksi dan kelas target, yang merupakan penerima siaran dalam kasus saya.
sumber