Làm cách nào để kiểm tra xem AlertManager đã có bộ báo thức chưa?


231

Khi ứng dụng của tôi khởi động, tôi muốn nó kiểm tra xem một báo thức cụ thể (đã đăng ký qua Báo thức quản lý) đã được đặt và chạy chưa. Kết quả từ google dường như chỉ ra rằng không có cách nào để làm điều này. Điều này vẫn đúng? Tôi cần thực hiện kiểm tra này để thông báo cho người dùng trước khi thực hiện bất kỳ hành động nào để tạo báo thức mới.


4
Vui lòng xác nhận câu trả lời đã giải quyết vấn đề của bạn hoặc đăng giải pháp của riêng bạn.
Anis

Câu trả lời:


322

Theo dõi các bình luận ron đăng, đây là giải pháp chi tiết. Giả sử bạn đã đăng ký báo thức lặp lại với mục đích đang chờ xử lý như sau:

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

Cách bạn sẽ kiểm tra xem nó có hoạt động hay không là:

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

Chìa khóa ở đây là FLAG_NO_CREATEcái như được mô tả trong javadoc: if the described PendingIntent **does not** already exists, then simply return null(thay vì tạo một cái mới)


9
Nó có phải sử dụng Intent chỉ với một chuỗi hành động không? Tôi đã thử chỉ định một lớp, Intent mới (bối cảnh, MyClass. Class) nhưng dường như nó không hoạt động. Nó luôn trả về null ngay cả khi báo thức đang chạy.
toc777

5
toc777, không cần nó phải là một Chuỗi khớp với một hành động được khai báo trong bộ lọc ý định của bạn trong tệp kê khai của bạn
Chris Knight

4
Chris, đó là một vấn đề khác gây ra vấn đề của tôi. Ý định tôi đã đề cập ở trên thực sự có hiệu quả :)
toc777

41
Lưu ý rằng bạn sẽ cần gọi cả hai alarmManager.cancel(pendingIntent)pendingIntent.cancel()để giải pháp này trả về sai.
Kevin Cooper

26
Trong trường hợp không rõ ràng, mã trong câu trả lời này không xác minh rằng mục đích đang chờ xử lý đã được đăng ký với trình quản lý báo động. Mã chỉ đơn giản xác minh rằng PendingIntent đã được tạo thông qua getBroadcast với mục đích tương đương. Bạn có thể chứng minh điều này bằng cách chạy mã alarmUp sau tất cả getBroadcast, nhưng trước tất cả các công cụ quản lý lịch và báo thức. Nó sẽ trở lại đúng sự thật. Thực tế này giải thích lý do tại sao bạn phải PendingIntent.celon để lấy giá trị trở về sai. Nói đúng ra, điều này không trả lời câu hỏi.
bigh_29

114

Đối với những người khác có thể cần điều này, đây là một câu trả lời.

Sử dụng adb shell dumpsys alarm

Bạn có thể biết báo thức đã được đặt và khi nào chúng sẽ báo động và ngắt quãng. Ngoài ra bao nhiêu lần báo động này đã được gọi.


36
Không thực sự là một câu trả lời có lập trình cho OP, nhưng là một mẹo hay. Rất tốt để biết.
JustSomeGuy

2
nối thêm một grep để lọc danh sách cảnh báo thường dài: adb shell dumpsys alarm | grep <e.g. package name of your app>Cũng hoạt động trên các Hệ thống Windows mới (tôi sử dụng Win10)
muetzenflo

3
grep được thực thi trên thiết bị di động, không phải PC của bạn. Vì vậy, nếu grep hoạt động phụ thuộc vào hệ điều hành Android. Điện thoại cũ không đi kèm với grep.
Henning

53

Ví dụ làm việc với người nhận (câu trả lời hàng đầu chỉ là bằng hành động).

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

Điều đáng nói là:

Nếu ứng dụng tạo sau này (quá trình) truy xuất lại cùng loại PendingIntent (cùng hoạt động , cùng ý định - hành động, dữ liệu, danh mục, thành phần, cờ ), nó sẽ nhận được PendingIntent đại diện cho cùng một mã thông báo nếu điều đó vẫn hợp lệ và do đó có thể gọi hủy () để loại bỏ nó.

Nói tóm lại, PendingIntent của bạn nên có cùng các tính năng (cấu trúc hoạt động và mục đích) để kiểm soát nó.


1
Tôi không chắc chắn rằng điều này là đủ. Trong trường hợp PendingIntent được đăng ký với Trình quản lý báo thức và sau đó bị dừng bởi cả hai phương thức hủy, 'isWorking' ở trên vẫn sẽ đúng. PendingIntent dường như chưa bị xóa khỏi Trình quản lý báo thức và sẽ tiếp tục trả về một thể hiện. Làm thế nào để chúng ta biết một cách hiệu quả khi báo động đã được bật / tắt?
johnDisplayClass

Điều này thực sự làm việc hoàn hảo. Những điều cần lưu ý: setAction () và requestCode () cần phải giống hệt nhau trong tất cả các getBroadcast () và giá trị của nó để gỡ cài đặt ứng dụng khỏi thiết bị của bạn. Điều đó bắt tôi ra ngoài. Cảm ơn
johnDisplayClass

Công trình tuyệt vời. Cảm ơn!
Ambran

1
Ví dụ hay nhưng tôi sẽ không sử dụng 1001 làm mã yêu cầu riêng tư ở đó. Chỉ cần 0 để làm cho ví dụ rõ ràng hơn.
Chris

1
Vui lòng không sử dụng "câu trả lời hàng đầu", v.v. Thay vào đó hãy cung cấp một liên kết đến câu trả lời. Bởi vì câu trả lời có thể thay đổi vị trí trên trang dựa trên mức độ phổ biến.
Kathir

44

Lưu ý trích dẫn này từ các tài liệu cho phương thức đã đặt của Trình quản lý báo thức:

Nếu đã có báo động cho Ý định này được lên lịch (với sự bằng nhau của hai ý định được xác định bởi Intent.filterEquals), thì nó sẽ bị xóa và được thay thế bằng ý định này.

Nếu bạn biết bạn muốn đặt báo thức, thì bạn không cần phải kiểm tra xem nó có tồn tại hay không. Chỉ cần tạo nó mỗi khi ứng dụng của bạn khởi động. Bạn sẽ thay thế bất kỳ báo động trong quá khứ bằng cùng Intent.

Bạn cần một cách tiếp cận khác nếu bạn đang cố gắng tính toán thời gian còn lại trên một báo thức được tạo trước đó hoặc nếu bạn thực sự cần biết liệu báo thức đó có tồn tại hay không. Để trả lời những câu hỏi đó, hãy xem xét việc lưu dữ liệu pref được chia sẻ tại thời điểm bạn tạo báo thức. Bạn có thể lưu trữ dấu thời gian của đồng hồ tại thời điểm báo thức được đặt, thời gian bạn mong muốn báo thức tắt và khoảng thời gian lặp lại (nếu bạn thiết lập báo thức lặp lại).


2
Theo tôi đây nên là câu trả lời được chấp nhận. Trừ khi OP có một tình huống đặc biệt biện minh cho việc không đặt lại báo thức
Jose_GD

Trong trường hợp của tôi, tôi muốn biết liệu báo thức đã được đặt chưa và nếu vậy tôi không muốn tạo báo thức mới hoặc đặt lại báo thức hiện có.
Imran Aslam

2
Câu trả lời tuyệt vời. Tại sao OP không kiểm tra điều này cả? Không có gì bạn cần làm.
Vijay Kumar Kanta

2
Có nhiều lỗ hổng trong giải pháp này, điều này có thể ghi đè thời gian báo thức được tạo trước đó (giả sử nếu thời gian cần được chỉ định như t + 24), vì vậy mỗi khi ứng dụng được khởi chạy, thời gian báo thức sẽ tiếp tục chuyển sang trạng thái mà nó không bao giờ có thể đạt được kích hoạt cho nhiều người, vì vậy kiểm tra báo động nếu nó đã tồn tại là đáng tin cậy hơn
Naga

10

Tôi có 2 báo động. Tôi đang sử dụng ý định với các tính năng bổ sung thay vì hành động để xác định các sự kiện:

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

điều này là với các tính năng bổ sung khác, ý định (và báo động) sẽ không phải là duy nhất. Vì vậy, để có thể xác định cảnh báo nào đang hoạt động hay không, tôi phải xác định diff requestCode-s:

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

và đây là cách báo thức được tạo ra:

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

Sử dụng các mục đích bổ sung và giải pháp này làm việc cho tôi. Chỉ có một thay đổi là tôi đang sử dụng dịch vụ nên tôi đã đổi nó thànhPendingIntent.getService
Pankaj

8

Chỉ cần tìm một giải pháp khác, nó dường như làm việc cho tôi

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

Đôi khi, trên Marshmallow, sau khi bạn buộc dừng ứng dụng, getBroadcast () sẽ trả về giá trị không, nhưng báo thức không được đặt.
hopia

6

Mặc dù hầu hết mọi người ở đây đã đưa ra câu trả lời chính xác, không có cơ quan nào giải thích trên cơ sở nào Báo thức hoạt động trên cơ sở nào

Bạn thực sự có thể tìm hiểu thêm về AlarmManagervà làm việc ở đây . Nhưng đây là câu trả lời nhanh

Bạn thấy AlarmManagervề cơ bản lịch trình một PendingIntentthời gian trong tương lai. Vì vậy, để hủy Báo thức theo lịch trình, bạn cần hủy PendingIntent.

Luôn lưu ý hai điều trong khi tạo PendingIntent

PendingIntent.getBroadcast(context,REQUEST_CODE,intent, PendingIntent.FLAG_UPDATE_CURRENT);
  • Mã yêu cầu - Hoạt động như mã định danh duy nhất
  • Cờ - Xác định hành vi của PendingIntent

Bây giờ để kiểm tra xem Báo thức đã được lên lịch hay để hủy Báo thức, bạn chỉ cần có quyền truy cập tương tự PendingIntent. Điều này có thể được thực hiện nếu bạn sử dụng cùng một mã yêu cầu và sử dụng FLAG_NO_CREATEnhư hiển thị bên dưới

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

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

Với FLAG_NO_CREATEnó sẽ trở lại nullnếu PendingIntentkhông tồn tại. Nếu nó đã tồn tại, nó trả về tham chiếu đến hiện tạiPendingIntent


Nếu Mã yêu cầu là mã định danh, điều quan trọng là phải vượt qua Ý định với Hành động phù hợp?
Sekula1991

Có cách nào để lấy thời gian báo thức được lên lịch với người báo thức nếu bạn có ý định chờ xử lý không?
M. Smith

4

Tôi đã tạo một tập lệnh bash đơn giản (ngu ngốc hoặc không), trích xuất các đoạn dài từ vỏ adb, chuyển đổi chúng thành dấu thời gian và hiển thị màu đỏ.

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

thử nó ;)


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 không tạo ra ý định chờ xử lý để nó mang lại giá trị boolean sai.

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

Sau khi Trình quản lý báo động kiểm tra giá trị của Ý định chờ xử lý, nó sẽ đúng vì Báo cáo của Trình quản lý báo cáo Cập nhật ý định đang chờ xử lý.

            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

Tôi có ấn tượng rằng không có cách nào để làm điều này, mặc dù nó sẽ tốt đẹp.

Bạn có thể đạt được kết quả tương tự bằng cách ghi lại Báo thức_last_set_time ở đâu đó và có On_boot_starter BroadcastReciever: BOOT_COMPLETED.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.