Bagaimana cara memeriksa apakah AlarmManager sudah memiliki set alarm?

231

Ketika aplikasi saya mulai, saya ingin memeriksa apakah alarm tertentu (terdaftar melalui AlarmManager) sudah diatur dan berjalan. Hasil dari google tampaknya menunjukkan bahwa tidak ada cara untuk melakukan ini. Apakah ini masih benar? Saya perlu melakukan pemeriksaan ini untuk memberi saran kepada pengguna sebelum tindakan apa pun diambil untuk membuat alarm baru.

ron
sumber
4
Harap validasi jawaban yang memecahkan masalah Anda atau kirim solusi Anda sendiri.
Anis

Jawaban:

322

Menindaklanjuti komentar yang diposting, berikut adalah solusi terperinci. Katakanlah Anda telah mendaftarkan alarm berulang dengan maksud tertunda seperti ini:

Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, 
                                      intent, PendingIntent.FLAG_UPDATE_CURRENT);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.MINUTE, 1);

AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), 1000 * 60, pendingIntent);

Cara Anda akan memeriksa untuk melihat apakah itu aktif adalah untuk:

boolean alarmUp = (PendingIntent.getBroadcast(context, 0, 
        new Intent("com.my.package.MY_UNIQUE_ACTION"), 
        PendingIntent.FLAG_NO_CREATE) != null);

if (alarmUp)
{
    Log.d("myTag", "Alarm is already active");
}

Kuncinya di sini adalah FLAG_NO_CREATEyang dijelaskan di javadoc: if the described PendingIntent **does not** already exists, then simply return null(alih-alih membuat yang baru)

Chris Knight
sumber
9
Apakah harus menggunakan Intent hanya dengan Action String? Saya mencoba menentukan kelas, Intent baru (konteks, MyClass.class) tetapi tampaknya tidak berhasil. Itu selalu mengembalikan nol bahkan ketika alarm sedang berjalan.
toc777
5
toc777, tidak itu harus menjadi String yang cocok dengan tindakan yang dinyatakan dalam filter maksud Anda di manifes.xml Anda
Chris Knight
4
Chris, itu masalah lain yang menyebabkan masalah saya. Maksud yang saya sebutkan di atas sebenarnya tidak berhasil :)
toc777
41
Perhatikan bahwa Anda harus memanggil keduanya alarmManager.cancel(pendingIntent)dan pendingIntent.cancel()agar solusi ini kembali salah.
Kevin Cooper
26
Jika tidak jelas, kode dalam jawaban ini tidak memverifikasi bahwa niat yang tertunda telah terdaftar pada manajer alarm. Kode hanya memverifikasi bahwa PendingIntent dibuat melalui getBroadcast dengan maksud target yang setara. Anda dapat membuktikan ini dengan menjalankan kode alarmUp setelah getBroadcast semua, tetapi sebelum semua hal-hal kalender dan manajer alarm. Itu akan kembali benar. Fakta ini menjelaskan mengapa Anda harus PendingIntent.cancel untuk mendapatkan nilai untuk kembali ke false. Sebenarnya, ini tidak menjawab pertanyaan.
bigh_29
114

Untuk orang lain yang mungkin membutuhkan ini, inilah jawabannya.

Menggunakan adb shell dumpsys alarm

Anda bisa tahu alarm telah diatur dan kapan mereka akan alarm dan interval. Juga berapa kali alarm ini dipanggil.

Jack Feng
sumber
36
Bukan benar-benar jawaban terprogram untuk OP, tetapi tip keren. Sangat bagus untuk diketahui.
JustSomeGuy
2
tambahkan grep untuk memfilter daftar alarm yang biasanya panjang: adb shell dumpsys alarm | grep <e.g. package name of your app>Juga berfungsi pada Sistem Windows baru (saya menggunakan Win10)
muetzenflo
3
grep dieksekusi pada perangkat seluler, bukan PC Anda. Jadi jika grep berfungsi tergantung pada OS Android. Ponsel lama tidak dilengkapi grep.
Henning
53

Contoh kerja dengan receiver (jawaban teratas hanya dengan tindakan).

//starting
AlarmManager alarmManager = (AlarmManager) getActivity().getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(getActivity(), MyReceiver.class);
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//my custom string action name
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//used unique ID as 1001
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis(), aroundInterval, pendingIntent);//first start will start asap

//and stopping
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
PendingIntent pendingIntent = PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_CANCEL_CURRENT);//the same as up
alarmManager.cancel(pendingIntent);//important
pendingIntent.cancel();//important

//checking if alarm is working with pendingIntent
Intent intent = new Intent(getActivity(), MyReceiver.class);//the same as up
intent.setAction(MyReceiver.ACTION_ALARM_RECEIVER);//the same as up
boolean isWorking = (PendingIntent.getBroadcast(getActivity(), 1001, intent, PendingIntent.FLAG_NO_CREATE) != null);//just changed the flag
Log.d(TAG, "alarm is " + (isWorking ? "" : "not") + " working...");

Perlu disebutkan:

Jika aplikasi pembuatan nanti (proses) mengambil kembali jenis PendingIntent yang sama ( operasi yang sama , maksud yang sama - tindakan, data, kategori, komponen, bendera ), ia akan menerima PendingIntent yang mewakili token yang sama jika itu masih valid, dan dengan demikian dapat memanggil cancel () untuk menghapusnya.

Singkatnya, PendingIntent Anda harus memiliki fitur yang sama (struktur operasi dan niat) untuk mengambil kendali atasnya.

ikan mati
sumber
1
Saya tidak yakin ini sudah cukup. Dalam kasus di mana PendingIntent terdaftar di AlarmManager dan kemudian dihentikan dengan kedua metode pembatalan, 'isWorking' di atas akan tetap benar. PendingIntent tampaknya belum dihapus dari AlarmManager, dan akan terus mengembalikan instance. Bagaimana kita mengetahui secara efektif kapan alarm dihidupkan / dimatikan?
johnDisplayClass
Ini sebenarnya bekerja dengan sempurna. Hal yang perlu diperhatikan: setAction () dan requestCode () harus identik di semua getBroadcast () dan perlu dicopot pemasangan aplikasinya dari perangkat Anda. Itu membuat saya tersadar. Terima kasih
johnDisplayClass
Bagus sekali. Terima kasih!
Ambran
1
Contoh yang bagus tapi saya tidak akan menggunakan 1001 sebagai kode permintaan pribadi di sana. Hanya 0 untuk membuat contoh lebih jelas.
Chris
1
Harap jangan menggunakan "jawaban atas" dll. Alih-alih berikan tautan ke jawabannya. Karena jawaban dapat mengubah posisi pada halaman berdasarkan popularitas.
Kathir
44

Perhatikan kutipan ini dari dokumen untuk metode yang ditetapkan Manajer Alarm:

Jika sudah ada alarm untuk Intent ini dijadwalkan (dengan kesetaraan dua niat yang didefinisikan oleh Intent.filterEquals), maka itu akan dihapus dan diganti dengan yang ini.

Jika Anda tahu Anda ingin alarm diatur, maka Anda tidak perlu repot memeriksa apakah sudah ada atau belum. Cukup buat setiap kali aplikasi Anda mem-boot. Anda akan mengganti alarm sebelumnya dengan yang sama Intent.

Anda memerlukan pendekatan yang berbeda jika Anda mencoba menghitung berapa banyak waktu yang tersisa pada alarm yang dibuat sebelumnya, atau jika Anda benar-benar perlu tahu apakah alarm semacam itu ada. Untuk menjawab pertanyaan-pertanyaan itu, pertimbangkan untuk menyimpan data preferensi bersama pada saat Anda membuat alarm. Anda dapat menyimpan timestamp jam pada saat alarm disetel, waktu yang Anda harapkan alarm berbunyi, dan periode berulang (jika Anda mengatur alarm berulang).

bigh_29
sumber
2
Menurut pendapat saya ini harus menjadi jawaban yang diterima. Kecuali OP memiliki situasi khusus yang membenarkan tidak mengulangi alarm
Jose_GD
Dalam kasus saya, saya ingin tahu apakah alarm sudah diatur dan jika demikian saya tidak ingin membuat yang baru atau mengatur ulang alarm yang ada.
Imran Aslam
2
Jawaban luar biasa. Mengapa OP tidak memeriksa ini sama sekali? Tidak ada yang perlu Anda lakukan.
Vijay Kumar Kanta
2
Ada banyak lubang loop dalam solusi ini, ini mungkin menimpa waktu alarm yang dibuat sebelumnya (katakanlah jika waktu perlu ditentukan seperti t + 24) sehingga setiap kali aplikasi diluncurkan waktu alarm terus bergerak maju keadaan yang tidak pernah bisa didapat pemicu bagi banyak orang, jadi memeriksa alarm jika sudah ada lebih dapat diandalkan
Naga
10

Saya memiliki 2 alarm. Saya menggunakan maksud dengan ekstra alih-alih tindakan untuk mengidentifikasi peristiwa:

Intent i = new Intent(context, AppReciever.class);
i.putExtra("timer", "timer1");

masalahnya adalah dengan diff ekstra maksud (dan alarm) tidak akan menjadi unik. Jadi untuk dapat mengidentifikasi alarm mana yang aktif atau tidak, saya harus mendefinisikan diff requestCode-s:

boolean alarmUp = (PendingIntent.getBroadcast(context, MyApp.TIMER_1, i, 
                    PendingIntent.FLAG_NO_CREATE) != null);

dan inilah cara alarm dibuat:

public static final int TIMER_1 = 1;
public static final int TIMER_2 = 2;

PendingIntent pending = PendingIntent.getBroadcast(context, TIMER_1, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);
pending = PendingIntent.getBroadcast(context, TIMER_2, i,
            PendingIntent.FLAG_CANCEL_CURRENT);
setInexactRepeating(AlarmManager.RTC_WAKEUP,
            cal.getTimeInMillis(), AlarmManager.INTERVAL_DAY, pending);
HiB
sumber
Menggunakan ekstra maksud dan solusi ini berhasil untuk saya. Hanya satu perubahan adalah saya menggunakan layanan jadi saya telah mengubahnya kePendingIntent.getService
Pankaj
8

Baru saja menemukan solusi lain, sepertinya berhasil untuk saya

Intent myIntent = new Intent(MainActivity.this, MyReceiver.class);

boolean isWorking = (PendingIntent.getBroadcast(MainActivity.this, 0, myIntent, PendingIntent.FLAG_NO_CREATE) != null);
if (isWorking) {Log.d("alarm", "is working");} else {Log.d("alarm", "is not working");}

if(!isWorking) {
    pendingIntent = PendingIntent.getBroadcast(MainActivity.this, 0, myIntent,    PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
    int timeNotif = 5 * 60 * 1000;//time in ms, 7*24*60*60*1000 for 1 week
    Log.d("Notif", "Notification every (ms): " + timeNotif);
    alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), timeNotif, pendingIntent);
    }
pengguna3856297
sumber
Terkadang, di Marshmallow, setelah Anda menghentikan paksa aplikasi, getBroadcast () akan mengembalikan non-null, tetapi alarm tidak disetel.
hopia
6

Sementara hampir semua orang di sini telah memberikan jawaban yang benar, tidak ada orang yang menjelaskan atas dasar apa Alarm bekerja

Anda sebenarnya dapat mempelajari lebih lanjut tentang AlarmManagerdan ini berfungsi di sini . Tapi inilah jawaban cepatnya

Anda AlarmManagerpada dasarnya melihat jadwal PendingIntentpada suatu waktu di masa depan. Jadi, untuk membatalkan Alarm yang dijadwalkan, Anda harus membatalkan PendingIntent.

Selalu perhatikan dua hal saat membuat PendingIntent

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • Kode Permintaan - Bertindak sebagai pengidentifikasi unik
  • Bendera - Menentukan perilaku PendingIntent

Sekarang untuk memeriksa apakah Alarm sudah dijadwalkan atau untuk membatalkan Alarm Anda hanya perlu mendapatkan akses yang sama PendingIntent. Ini dapat dilakukan jika Anda menggunakan kode permintaan yang sama dan menggunakan FLAG_NO_CREATEseperti yang ditunjukkan di bawah ini

PendingIntent pendingIntent=PendingIntent.getBroadcast(this,REQUEST_CODE,intent,PendingIntent.FLAG_NO_CREATE);

if (pendingIntent!=null)
   alarmManager.cancel(pendingIntent);

Dengan FLAG_NO_CREATEitu akan kembali nulljika PendingIntentbelum ada. Jika sudah ada itu mengembalikan referensi ke yang sudah adaPendingIntent

IrshadKumail
sumber
Jika Kode Permintaan adalah pengidentifikasi, apakah penting untuk lulus Intent dengan Aksi yang cocok?
Sekula1991
Apakah ada cara untuk mendapatkan waktu alarm dijadwalkan dengan alarmanager jika Anda memiliki niat tertunda?
M. Smith
4

Saya membuat skrip bash sederhana (bodoh atau tidak), yang mengekstrak long dari adb shell, mengubahnya menjadi cap waktu dan menunjukkannya dalam warna merah.

echo "Please set a search filter"
read search

adb shell dumpsys alarm | grep $search | (while read i; do echo $i; _DT=$(echo $i | grep -Eo 'when\s+([0-9]{10})' | tr -d '[[:alpha:][:space:]]'); if [ $_DT ]; then echo -e "\e[31m$(date -d @$_DT)\e[0m"; fi; done;)

Cobalah ;)

Jan Ni
sumber
1
    Intent intent = new Intent("com.my.package.MY_UNIQUE_ACTION");
            PendingIntent pendingIntent = PendingIntent.getBroadcast(
                    sqlitewraper.context, 0, intent,
                    PendingIntent.FLAG_NO_CREATE);

FLAG_NO_CREATE tidak membuat pending intent sehingga memberikan nilai boolean salah.

            boolean alarmUp = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_NO_CREATE) != null);

            if (alarmUp) {
                System.out.print("k");

            }

            AlarmManager alarmManager = (AlarmManager) sqlitewraper.context
                    .getSystemService(Context.ALARM_SERVICE);
            alarmManager.setRepeating(AlarmManager.RTC_WAKEUP,
                    System.currentTimeMillis(), 1000 * 60, pendingIntent);

Setelah AlarmManager memeriksa nilai Pending Intent, itu memberikan kebenaran karena AlarmManager Memperbarui Bendera Inting Pending.

            boolean alarmUp1 = (PendingIntent.getBroadcast(sqlitewraper.context, 0,
                    new Intent("com.my.package.MY_UNIQUE_ACTION"),
                    PendingIntent.FLAG_UPDATE_CURRENT) != null);
            if (alarmUp1) {
                System.out.print("k");

            }
MIkka Marmik
sumber
0

Saya di bawah kesan bahwa tidak ada cara untuk melakukan ini, akan lebih baik.

Anda dapat mencapai hasil yang serupa dengan membuat Alarm_last_set_time direkam di suatu tempat, dan memiliki On_boot_starter BroadcastReciever: BOOT_COMPLETED agak aneh.

Stephen
sumber