จะตรวจสอบว่า AlarmManager มีการตั้งปลุกได้อย่างไร?


231

เมื่อแอพของฉันเริ่มต้นฉันต้องการให้มันตรวจสอบว่ามีการตั้งค่าและเรียกใช้สัญญาณเตือน (ลงทะเบียนผ่าน AlarmManager) โดยเฉพาะหรือไม่ ผลลัพธ์จาก google ดูเหมือนจะบ่งบอกว่าไม่มีทางทำเช่นนี้ ยังคงถูกต้องหรือไม่ ฉันต้องทำการตรวจสอบนี้เพื่อให้คำแนะนำผู้ใช้ก่อนที่จะดำเนินการใด ๆ เพื่อสร้างการเตือนภัยใหม่


4
โปรดตรวจสอบคำตอบที่แก้ไขปัญหาของคุณหรือโพสต์โซลูชั่นของคุณเอง
Anis

คำตอบ:


322

ติดตามความคิดเห็น ron ที่โพสต์ต่อไปนี้เป็นวิธีแก้ไขปัญหาโดยละเอียด สมมติว่าคุณได้ลงทะเบียนการเตือนซ้ำด้วยความตั้งใจที่รอดำเนินการเช่นนี้:

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

วิธีที่คุณจะตรวจสอบเพื่อดูว่ามันใช้งานอยู่คือ:

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

กุญแจนี่คือรหัสตามFLAG_NO_CREATEที่อธิบายไว้ใน javadoc: if the described PendingIntent **does not** already exists, then simply return null(แทนที่จะสร้างใหม่)


9
จำเป็นต้องใช้ Intent ด้วย Action String หรือไม่? ฉันพยายามระบุคลาส, เจตนาใหม่ (บริบท, MyClass.class) แต่ดูเหมือนจะไม่ทำงาน มันจะคืนค่าเป็นโมฆะเสมอแม้ในขณะที่สัญญาณเตือนทำงาน
toc777

5
toc777 ไม่จำเป็นต้องเป็นสตริงที่ตรงกับการกระทำที่ประกาศไว้ในตัวกรองเจตนาของคุณใน manifest.xml ของคุณ
Chris Knight

4
คริสมันเป็นอีกปัญหาหนึ่งที่ทำให้เกิดปัญหาของฉัน ความตั้งใจที่ฉันกล่าวถึงข้างต้นใช้งานได้จริง :)
toc777

41
โปรดทราบว่าคุณจะต้องโทรหาทั้งสองalarmManager.cancel(pendingIntent)และpendingIntent.cancel()เพื่อให้วิธีนี้กลับเท็จ
Kevin Cooper

26
ในกรณีที่ไม่ชัดเจนรหัสในคำตอบนี้ไม่ได้ตรวจสอบว่ามีการลงทะเบียนความตั้งใจที่รอดำเนินการกับผู้จัดการปลุก รหัสเพียงตรวจสอบว่า PendingIntent ถูกสร้างขึ้นผ่าน getBroadcast ด้วยเป้าหมายที่เทียบเท่า คุณสามารถพิสูจน์ได้ด้วยการเรียกใช้รหัส alarmUp หลังจาก getBroadcast ทั้งหมด แต่ก่อนหน้าสิ่งที่ปฏิทินและตัวจัดการสัญญาณเตือนทั้งหมด มันจะกลับมาจริง ข้อเท็จจริงนี้อธิบายว่าทำไมคุณต้องรอ PendingIntent.cancel เพื่อรับค่าเพื่อกลับไปเป็นเท็จ พูดอย่างเคร่งครัดนี่ไม่ได้ตอบคำถาม
bigh_29

114

สำหรับคนอื่นที่อาจต้องการสิ่งนี้นี่คือคำตอบ

ใช้ adb shell dumpsys alarm

คุณสามารถทราบได้ว่าตั้งปลุกแล้วและจะแจ้งเตือนเมื่อใด นอกจากนี้มีการเรียกใช้การเตือนนี้กี่ครั้ง


36
ไม่ใช่คำตอบที่เป็นโปรแกรมสำหรับ OP แต่เป็นคำแนะนำเด็ด ๆ ดีมากที่จะรู้
JustSomeGuy

2
ผนวก grep เพื่อกรองรายการการเตือนที่มักจะยาว: adb shell dumpsys alarm | grep <e.g. package name of your app>ทำงานบนระบบ Windows ใหม่ (ฉันใช้ Win10)
muetzenflo

3
grep ถูกดำเนินการบนอุปกรณ์พกพาไม่ใช่พีซีของคุณ ดังนั้นหาก grep ทำงานได้ขึ้นกับระบบปฏิบัติการ Android โทรศัพท์รุ่นเก่าไม่มี grep
Henning

53

ตัวอย่างการทำงานกับผู้รับ

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

เป็นมูลค่าการกล่าวถึง:

หากแอปพลิเคชันการสร้างในภายหลัง (กระบวนการ) เรียกคืน PendingIntent ชนิดเดียวกัน ( การดำเนินการเดียวกันIntent'sเดียวกัน- การกระทำข้อมูลหมวดหมู่ส่วนประกอบแฟล็ก ) จะได้รับ PendingIntent ที่แสดงโทเค็นเดียวกันหากยังคงถูกต้องและ สามารถโทรยกเลิก () เพื่อลบได้

กล่าวโดยสรุปว่า PendingIntent ของคุณควรมีคุณสมบัติเหมือนกัน (โครงสร้างการทำงานและโครงสร้างของเจตนา) เพื่อควบคุม


1
ฉันไม่แน่ใจว่าเพียงพอ ในกรณีที่มีการลงทะเบียน PendingIntent กับ AlarmManager แล้วหยุดโดยวิธีการยกเลิกทั้งสอง 'isWorking' ด้านบนจะยังคงเป็นจริง PendingIntent ดูเหมือนว่ายังไม่ได้ถูกลบออกจาก AlarmManager และจะกลับมาอินสแตนซ์ จากนั้นเราจะรู้ได้อย่างมีประสิทธิภาพเมื่อเปิด / ปิดสัญญาณเตือนได้อย่างไร
johnDisplayClass

มันใช้งานได้จริงอย่างสมบูรณ์ สิ่งที่ควรทราบ: setAction () และ requestCode () จะต้องเหมือนกันในทุก getBroadcast () และค่าควรถอนการติดตั้งแอปจากอุปกรณ์ของคุณ ที่จับฉันออก ขอบคุณ
johnDisplayClass

ใช้งานได้ดี ขอบคุณ!
Ambran

1
ตัวอย่างที่ดี แต่ฉันจะไม่ใช้ 1001 เป็นรหัสคำขอส่วนตัวที่นั่น แค่ 0 เพื่อทำให้ตัวอย่างชัดเจนขึ้น
Chris

1
โปรดงดเว้นจากการใช้ "คำตอบยอดนิยม" ฯลฯ ให้ระบุลิงก์ไปยังคำตอบแทน เพราะคำตอบสามารถเปลี่ยนตำแหน่งในหน้าได้ตามความนิยม
Kathir

44

สังเกตคำพูดนี้จากเอกสารสำหรับวิธีการตั้งค่าของ Alarm Manager:

หากมีการเตือนสำหรับเจตนาที่กำหนดไว้นี้แล้ว (ด้วยความเท่าเทียมกันของสอง intent ที่กำหนดโดย Intent.filterEquals) แล้วมันจะถูกลบออกและแทนที่ด้วยหนึ่งนี้

หากคุณรู้ว่าคุณต้องการชุดสัญญาณเตือนคุณไม่ต้องกังวลกับการตรวจสอบว่ามีอยู่แล้วหรือไม่ เพียงสร้างมันทุกครั้งที่บูทแอปของคุณ คุณจะเข้ามาแทนที่การเตือนภัยที่ผ่านมาใด ๆ Intentด้วยเหมือนกัน

คุณต้องการวิธีการที่แตกต่างกันหากคุณกำลังพยายามคำนวณเวลาที่เหลืออยู่ในการเตือนที่สร้างไว้ก่อนหน้านี้หรือถ้าคุณต้องการทราบว่าการเตือนดังกล่าวมีอยู่จริงหรือไม่ ในการตอบคำถามเหล่านั้นให้พิจารณาบันทึกข้อมูลที่แบ่งปันล่วงหน้าในเวลาที่คุณสร้างการเตือน คุณสามารถจัดเก็บการประทับเวลาของนาฬิกาในขณะที่ตั้งค่าการเตือนเวลาที่คุณคาดว่าการเตือนจะดับลงและระยะเวลาการทำซ้ำ (ถ้าคุณตั้งค่าการเตือนซ้ำ)


2
ในความคิดของฉันนี้ควรเป็นคำตอบที่ยอมรับ เว้นแต่ OP จะมีสถานการณ์พิเศษที่แสดงว่าไม่ได้ปรับสัญญาณเตือนภัย
Jose_GD

ในกรณีของฉันฉันต้องการทราบว่าตั้งปลุกแล้วและถ้าเป็นเช่นนั้นฉันไม่ต้องการสร้างใหม่หรือตั้งปลุกที่มีอยู่
Imran Aslam

2
คำตอบที่ยอดเยี่ยม ทำไม OP ถึงไม่ตรวจสอบเรื่องนี้เลย? ไม่มีอะไรที่คุณต้องทำ
Vijay Kumar Kanta

2
มีรูวนมากในโซลูชันนี้อาจแทนที่เวลาปลุกที่สร้างไว้ก่อนหน้านี้ (ให้บอกว่าถ้าต้องระบุเวลาเช่น t + 24) ดังนั้นทุกครั้งที่แอปเปิดตัวเวลาปลุกจะทำให้เดินต่อไปสู่สถานะที่ไม่สามารถรับได้ ทริกเกอร์สำหรับหลาย ๆ คนดังนั้นการตรวจสอบสัญญาณเตือนถ้ามีอยู่แล้วน่าเชื่อถือมากขึ้น
Naga

10

ฉันมี 2 สัญญาณเตือน ฉันใช้ความตั้งใจด้วยความพิเศษแทนการกระทำเพื่อระบุเหตุการณ์:

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

สิ่งนั้นคือด้วยความตั้งใจที่แตกต่างกัน (และสัญญาณเตือน) จะไม่ซ้ำกัน ดังนั้นเพื่อระบุว่าการเตือนใดที่เปิดใช้งานอยู่หรือไม่ฉันต้องกำหนด diff requestCode-s:

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

และนี่คือวิธีสร้างสัญญาณเตือน:

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

การใช้ความตั้งใจพิเศษและวิธีนี้ใช้ได้ผลสำหรับฉัน มีเพียงการเปลี่ยนแปลงเดียวที่ฉันใช้บริการดังนั้นฉันจึงเปลี่ยนเป็นPendingIntent.getService
Pankaj

8

เพิ่งพบวิธีแก้ปัญหาอื่นดูเหมือนว่าจะทำงานให้ฉัน

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

บางครั้งบน Marshmallow หลังจากที่คุณบังคับให้หยุดแอพ getBroadcast () จะกลับมาเป็นค่าที่ไม่เป็นโมฆะ แต่ไม่มีการตั้งค่าการเตือน
hopia

6

ในขณะที่เกือบทุกคนที่นี่ให้คำตอบที่ถูกต้อง แต่ไม่มีเนื้อหาใดที่อธิบายว่าสัญญาณเตือนทำงานอย่างไร

จริงๆคุณสามารถเรียนรู้เพิ่มเติมเกี่ยวกับการAlarmManagerและการทำงานของที่นี่ แต่นี่คือคำตอบด่วน

คุณจะเห็นAlarmManagerตารางเวลาโดยทั่วไปPendingIntentในอนาคต PendingIntentดังนั้นเพื่อที่จะยกเลิกการเตือนภัยที่กำหนดไว้ที่คุณจำเป็นต้องยกเลิก

จดบันทึกสองสิ่งเสมอในขณะที่สร้าง PendingIntent

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • ขอรหัส - ทำหน้าที่เป็นตัวระบุที่ไม่ซ้ำกัน
  • ตั้งค่าสถานะ - กำหนดพฤติกรรมของ PendingIntent

PendingIntentตอนนี้เพื่อตรวจสอบว่าการเตือนภัยที่กำหนดไว้แล้วหรือที่จะยกเลิกการเตือนภัยคุณเพียงแค่ต้องได้รับการเข้าถึงเดียวกัน สิ่งนี้สามารถทำได้หากคุณใช้รหัสคำขอเดียวกันและใช้ตามที่FLAG_NO_CREATEแสดงด้านล่าง

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

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

ด้วยFLAG_NO_CREATEมันจะกลับมาnullถ้าPendingIntentไม่มีอยู่ หากมีอยู่แล้วจะส่งคืนการอ้างอิงถึงที่มีอยู่PendingIntent


หากรหัสคำขอเป็นตัวระบุจำเป็นต้องส่งการแสดงเจตนาด้วยการกระทำที่ตรงกันหรือไม่?
Sekula1991

มีวิธีที่จะได้รับเวลาที่มีการเตือนภัยที่กำหนดไว้กับ alarmanager ถ้าคุณมีความตั้งใจที่ค้างอยู่?
M. Smith

4

ฉันสร้างสคริปต์ทุบตีเรียบง่าย (โง่หรือไม่) ซึ่งแยกความยาวจากเชลล์ adb แปลงเป็น timestamps และแสดงเป็นสีแดง

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

ลองมัน ;)


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 ไม่ได้สร้างเจตนาที่ค้างอยู่เพื่อให้ค่าบูลีนเป็นเท็จ

            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 ตรวจสอบค่าของ Intent Intent มันจะเป็นจริงเพราะ AlarmManager Update ค่าสถานะของ Intent ที่รออยู่

            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

ฉันอยู่ภายใต้ความประทับใจที่ไม่มีทางทำสิ่งนี้ได้

คุณสามารถบรรลุผลลัพธ์ที่คล้ายกันโดยการบันทึก Alarm_last_set_time ที่ไหนสักแห่งและมี On_boot_starter BroadcastReciever: BOOT_COMPLETED

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.