AlarmManager'da önceden ayarlanmış bir alarm olup olmadığı nasıl kontrol edilir?


231

Uygulamam başladığında, belirli bir alarmın (AlarmManager aracılığıyla kaydedildi) önceden ayarlanmış ve çalışıyor olup olmadığını kontrol etmesini istiyorum. Google'dan alınan sonuçlar, bunu yapmanın bir yolu olmadığını gösteriyor. Bu hala doğru mu? Yeni bir alarm oluşturmak için herhangi bir işlem yapılmadan önce kullanıcıya tavsiyede bulunmak için bu kontrolü yapmam gerekiyor.


4
Lütfen sorununuzu çözen yanıtı doğrulayın veya kendi çözümünüzü gönderin.
Anis

Yanıtlar:


322

Gönderilen ron'u takip ederek, ayrıntılı çözüm. Diyelim ki beklemede olan bir niyetle tekrar eden bir alarm kaydettiniz:

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);

Aktif olup olmadığını kontrol etmenin yolu:

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");
}

Buradaki anahtar FLAG_NO_CREATE, javadoc'ta açıklandığı gibidir: if the described PendingIntent **does not** already exists, then simply return null(yeni bir tane oluşturmak yerine)


9
Niyeti yalnızca bir Action String ile kullanmak zorunda mı? Bir sınıf, yeni niyet (bağlam, MyClass.class) belirlemeye çalıştım ama işe yaramıyor gibi görünüyor. Alarm çalışırken bile null değerini döndürür.
toc777

5
toc777, hayır, manifest.xml dosyasındaki niyet filtrenizde bildirilen bir eylemle eşleşen bir Dize olması gerekiyor
Chris Knight

4
Chris, Sorunumun sebebi başka bir konuydu. Yukarıda bahsettiğim niyet aslında işe yarıyor :)
toc777

41
Her iki çağrı gerekeceğini Not alarmManager.cancel(pendingIntent)ve pendingIntent.cancel()return false bu çözüm için sırayla.
Kevin Cooper

26
Açıkça görülmüyorsa, bu yanıttaki kod beklemede olan hedefin alarm yöneticisine kaydedildiğini doğrulamaz. Kod, PendingIntent öğesinin getBroadcast aracılığıyla eşdeğer bir hedef niyetiyle oluşturulduğunu doğrular. Bunu getBroadcast hepsinden sonra, ancak tüm takvim ve alarm yöneticisi öğelerinden önce alarmUp kodunu çalıştırarak kanıtlayabilirsiniz. Doğru dönecektir. Bu gerçek, değeri false değerine geri döndürmek için neden PendingIntent.cancel'e ihtiyacınız olduğunu açıklar. Açıkçası, bu soruya cevap vermiyor.
bigh_29

114

Buna ihtiyaç duyanlar için işte bir cevap.

kullanım adb shell dumpsys alarm

Alarmın kurulduğunu ve ne zaman alarm vereceğine ve zaman aralığına gireceğini öğrenebilirsiniz. Ayrıca bu alarmın kaç kez çağrıldığını.


36
OP'ye gerçekten programatik bir cevap değil, havalı bir ipucu. Bilmek çok güzel.
JustSomeGuy

2
genellikle uzun alarm listesini filtrelemek için bir grep ekleyin: adb shell dumpsys alarm | grep <e.g. package name of your app>Ayrıca yeni Windows Sistemlerinde de çalışır (Win10 kullanıyorum)
muetzenflo

3
grep PC'nizde değil mobil cihazınızda yürütülür. Yani grep çalışırsa Android işletim sistemine bağlıdır. Eski telefonlar grep ile gelmiyor.
Henning

53

Alıcı ile çalışma örneği (en iyi cevap sadece eylemdi).

//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...");

Bahsetmeye değer:

Oluşturma uygulaması daha sonra (işlem) aynı PendingIntent türünü yeniden alırsa (aynı işlem , aynı Niyet - eylem, veri, kategoriler, bileşenler, bayraklar ), hala geçerliyse aynı belirteci temsil eden bir PendingIntent alır ve bu nedenle kaldırmak için cancel () öğesini çağırabilir.

Kısacası, PendingIntent'iniz kontrolü ele geçirmek için aynı özelliklere (operasyon ve niyetin yapısı) sahip olmalıdır.


1
Bunun yeterli olduğundan emin değilim. Bir PendingIntent'in AlarmManager'a kaydedilmesi ve ardından her iki iptal yöntemiyle durdurulması durumunda, yukarıdaki 'isWorking' hala geçerli olacaktır. PendingIntent, AlarmManager'dan kaldırılmamış gibi görünüyor ve bir örnek döndürmeye devam edecek. Alarmların ne zaman açılıp kapatıldığını nasıl etkili bir şekilde biliriz?
16:36

Bu gerçekten mükemmel çalıştı. Dikkat edilmesi gerekenler: setAction () ve requestCode () öğelerinin tüm getBroadcast () 'lerde aynı olması ve uygulamayı cihazınızdan kaldırmaya değer olması gerekir. Bu beni yakaladı. Teşekkürler
johnDisplayClass

Harika çalışıyor. Teşekkürler!
Ambran

1
Güzel bir örnek ama orada özel istek kodu olarak 1001 kullanmazdım. Örneği daha açık hale getirmek için sadece 0.
Chris

1
Lütfen "en iyi cevap" vb. Kullanmaktan kaçının. Bunun yerine cevaba bir link verin. Çünkü yanıtlar sayfadaki konumları popülerliğe göre değiştirebilir.
Kathir

44

Not Bu teklifi Alarm Manager kümesi yöntemi için dokümanlardan:

Bu Amaç için önceden planlanmış bir alarm varsa (Intent.filterEquals tarafından tanımlanan iki niyetin eşitliği ile), o zaman kaldırılır ve bu alarmla değiştirilir.

Alarmın ayarlanmasını istediğinizi biliyorsanız, önceden var olup olmadığını kontrol etmenize gerek yoktur. Uygulamanız her önyüklendiğinde oluşturun. Geçmiş alarmları aynı ile değiştireceksiniz Intent.

Önceden oluşturulmuş bir alarmda ne kadar süre kaldığını hesaplamaya çalışıyorsanız veya bu alarmın var olup olmadığını gerçekten bilmeniz gerekiyorsa farklı bir yaklaşıma ihtiyacınız vardır. Bu soruları cevaplamak için alarmı oluşturduğunuzda paylaşılan tercih verilerini kaydetmeyi düşünün. Saat zaman damgasını alarmın ayarlandığı anda, alarmın çalmasını beklediğiniz zamanı ve tekrar periyodunu (tekrar eden bir alarm ayarlarsanız) kaydedebilirsiniz.


2
Bence bu kabul edilen cevap olmalı. OP'nin alarmı yeniden düzenlememeyi haklı gösteren özel bir durumu yoksa
Jose_GD

Benim durumumda, alarmın önceden ayarlanmış olup olmadığını bilmek ve eğer öyleyse yeni bir tane oluşturmak veya mevcut alarmı sıfırlamak istemiyorum.
Imran Aslam

2
Mükemmel cevap. OP bunu neden kontrol etmedi? Yapman gereken bir şey yok.
Vijay Kumar Kanta

2
Bu çözümde çok sayıda döngü deliği vardır, bu daha önce oluşturulmuş alarm süresini geçersiz kılabilir (zamanın t + 24 gibi belirtilmesi gerekiyorsa diyelim), böylece uygulama her başlatıldığında alarm süresi ilerleyemeyeceği bir durumu ilerlemeye devam eder birçoğu için tetikleme, bu yüzden alarmın zaten mevcut olup olmadığını kontrol etmek daha güvenilirdir
Naga

10

2 alarmım var. Olayları tanımlamak için eylem yerine ekstralar ile niyet kullanıyorum:

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

şey, fark ekstraları ile niyet (ve alarm) benzersiz olmayacak olmasıdır. Hangi alarmın aktif olup olmadığını belirlemek için diff requestCode-s tanımlamak zorunda kaldım :

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

ve alarm şu şekilde oluşturuldu:

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);

Niyet ekstralarını ve bu çözümü kullanmak benim için çalıştı. Sadece bir değişiklik hizmet kullanıyorum, bu yüzden bunu değiştirdimPendingIntent.getService
Pankaj

8

Başka bir çözüm buldum, benim için çalışıyor gibi görünüyor

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);
    }

Bazen, Marshmallow'da, bir uygulamayı zorla durdurduktan sonra getBroadcast () null değerine geri döner, ancak alarm ayarlanmaz.
hopia

6

Buradaki neredeyse herkes doğru cevabı vermiş olsa da, Alarmlar hangi temelde çalışır?

BuradaAlarmManager ve onun çalışması hakkında daha fazla bilgi edinebilirsiniz . Ama işte hızlı cevap

AlarmManagerTemelde PendingIntentgelecekte bir zaman çizelgeleri görürsünüz . Bu nedenle, planlanan Alarmı iptal etmek için PendingIntent.

Oluştururken her zaman iki şeyi not edin PendingIntent

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • İstek Kodu - Benzersiz tanımlayıcı görevi görür
  • İşaretle - İşaretinin davranışını tanımlar. PendingIntent

Şimdi Alarmın önceden programlanmış olup olmadığını kontrol etmek veya Alarmı iptal etmek için sadece buna erişmeniz gerekir PendingIntent. Bu, aynı istek kodunu ve FLAG_NO_CREATEaşağıda gösterildiği gibi kullanırsanız yapılabilir

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

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

İle FLAG_NO_CREATEbuna dönecektir nulleğer PendingIntentzaten yok. Zaten mevcutsa, mevcut olana referans döndürürPendingIntent


İstek Kodu bir tanımlayıcıysa, Niyet ile eşleşen Eylemi iletmek önemli mi?
Sekula1991

Bekleyen niyetiniz varsa alarmın alarmanager ile planlandığı zamanı almanın bir yolu var mı?
M. Smith

4

Adb kabuğundan uzunları ayıklayan, zaman damgalarına dönüştüren ve kırmızı renkte gösteren basit (aptal veya değil) bir bash betiği yaptım.

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;)

dene ;)


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, boole değeri false değerini verecek şekilde beklemede olan amaç oluşturmuyor.

            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);

AlarmManager Beklemede Niyet değerini kontrol ettikten sonra, AlarmManager Beklemede Niyet Bayrağını Güncellediği için true değerini verir.

            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");

            }

0

Bunu yapmanın bir yolu olmadığı izlenimi altındayım, ama güzel olurdu.

Bir yere Alarm_last_set_time kaydedip On_boot_starter BroadcastReciever: BOOT_COMPLETED türünde bir şey elde ederek benzer bir sonuç elde edebilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.